# HG changeset patch # User Tom Henderson # Date 1294037852 28800 # Node ID 7ff69b244b5b0da83dd63c1bf467d0727e9c2aeb # Parent c9133c87760da6fe0889bd646006a4ba80144887 Move tutorial to Sphinx diff -r c9133c87760d -r 7ff69b244b5b doc/tutorial/Makefile --- a/doc/tutorial/Makefile Sun Jan 02 22:57:04 2011 -0800 +++ b/doc/tutorial/Makefile Sun Jan 02 22:57:32 2011 -0800 @@ -1,39 +1,150 @@ -TEXI2HTML = texi2html -TEXI2PDF = texi2dvi --pdf -EPSTOPDF = epstopdf +# Makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +PAPER = +BUILDDIR = build + +# Internal variables. +PAPEROPT_a4 = -D latex_paper_size=a4 +PAPEROPT_letter = -D latex_paper_size=letter +ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source + +# Additional variables for figures, not sphinx default: DIA = dia -CONVERT = convert -CSS = --css-include=tutorial.css -SPLIT = --split section +EPSTOPDF = epstopdf +FIGURES = source/figures +IMAGES_EPS = \ + +IMAGES_PNG = ${IMAGES_EPS:.eps=.png} +IMAGES_PDF = ${IMAGES_EPS:.eps=.pdf} + +IMAGES = $(IMAGES_EPS) $(IMAGES_PNG) $(IMAGES_PDF) + +.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest + +%.eps : %.dia; $(DIA) -t eps $< -e $@ +%.png : %.dia; $(DIA) -t png $< -e $@ +%.pdf : %.eps; $(EPSTOPDF) $< -o=$@ -DIA_SOURCES = pp.dia dumbbell.dia star.dia +help: + @echo "Please use \`make ' where is one of" + @echo " html to make standalone HTML files" + @echo " dirhtml to make HTML files named index.html in directories" + @echo " singlehtml to make a single large HTML file" + @echo " pickle to make pickle files" + @echo " json to make JSON files" + @echo " htmlhelp to make HTML files and a HTML help project" + @echo " qthelp to make HTML files and a qthelp project" + @echo " devhelp to make HTML files and a Devhelp project" + @echo " epub to make an epub" + @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" + @echo " latexpdf to make LaTeX files and run them through pdflatex" + @echo " text to make text files" + @echo " man to make manual pages" + @echo " changes to make an overview of all changed/added/deprecated items" + @echo " linkcheck to check all external links for integrity" + @echo " doctest to run all doctests embedded in the documentation (if enabled)" -DIA_EPS = ${DIA_SOURCES:.dia=.eps} -DIA_PNG = ${DIA_SOURCES:.dia=.png} -DIA_PDF = ${DIA_SOURCES:.dia=.pdf} +clean: + -rm -rf $(BUILDDIR)/* + +frag: pickle + @if test ! -d $(BUILDDIR)/frag; then mkdir $(BUILDDIR)/frag; fi + pushd $(BUILDDIR)/frag && ../../pickle-to-xml.py ../pickle/index.fpickle > navigation.xml && popd + cp -r $(BUILDDIR)/pickle/_images $(BUILDDIR)/frag -all: html split-html pdf +html: $(IMAGES) + $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." + +dirhtml: $(IMAGES) + $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." + +singlehtml: $(IMAGES) + $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml + @echo + @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." -# Note: tgif requires a valid x display to convert from .obj to .png. -# If running this makefile on a remote console, the X virtual frame -# buffer may be needed (xorg-x11-server-Xvfb) to provide a "fake" -# display -images: - cd figures/; $(DIA) -t png $(DIA_SOURCES) - cd figures/; $(DIA) -t eps $(DIA_SOURCES) - cd figures/; $(foreach FILE,$(DIA_EPS),$(EPSTOPDF) $(FILE);) +pickle: $(IMAGES) + $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle + @echo + @echo "Build finished; now you can process the pickle files." + +json: $(IMAGES) + $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json + @echo + @echo "Build finished; now you can process the JSON files." + +htmlhelp: $(IMAGES) + $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp + @echo + @echo "Build finished; now you can run HTML Help Workshop with the" \ + ".hhp project file in $(BUILDDIR)/htmlhelp." -html: - $(TEXI2HTML) ${CSS} tutorial.texi +qthelp: $(IMAGES) + $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp + @echo + @echo "Build finished; now you can run "qcollectiongenerator" with the" \ + ".qhcp project file in $(BUILDDIR)/qthelp, like this:" + @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/ns-3.qhcp" + @echo "To view the help file:" + @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/ns-3.qhc" + +devhelp: $(IMAGES) + $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp + @echo + @echo "Build finished." + @echo "To view the help file:" + @echo "# mkdir -p $$HOME/.local/share/devhelp/ns-3" + @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/ns-3" + @echo "# devhelp" + +epub: $(IMAGES) + $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub + @echo + @echo "Build finished. The epub file is in $(BUILDDIR)/epub." -split-html: - $(TEXI2HTML) ${CSS} ${SPLIT} --output tutorial tutorial.texi +latex: $(IMAGES) + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo + @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." + @echo "Run \`make' in that directory to run these through (pdf)latex" \ + "(use \`make latexpdf' here to do that automatically)." -pdf: - $(TEXI2PDF) tutorial.texi +latexpdf: $(IMAGES) + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through pdflatex..." + make -C $(BUILDDIR)/latex all-pdf + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +text: $(IMAGES) + $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text + @echo + @echo "Build finished. The text files are in $(BUILDDIR)/text." -figures-clean: - cd figures/; rm -rf $(DIA_EPS); rm -rf $(DIA_PNG); rm -rf $(DIA_PDF) +man: $(IMAGES) + $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man + @echo + @echo "Build finished. The manual pages are in $(BUILDDIR)/man." + +changes: $(IMAGES) + $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes + @echo + @echo "The overview file is in $(BUILDDIR)/changes." -clean: # figures-clean - rm -rf tutorial.aux tutorial.cp tutorial.cps tutorial.fn tutorial.ky tutorial.pg tutorial.tp tutorial.vr tutorial.toc tutorial.log tutorial.pdf tutorial.html tutorial/ +linkcheck: $(IMAGEs) + $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck + @echo + @echo "Link check complete; look for any errors in the above output " \ + "or in $(BUILDDIR)/linkcheck/output.txt." + +doctest: $(IMAGES) + $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest + @echo "Testing of doctests in the sources finished, look at the " \ + "results in $(BUILDDIR)/doctest/output.txt." diff -r c9133c87760d -r 7ff69b244b5b doc/tutorial/building-topologies.texi --- a/doc/tutorial/building-topologies.texi Sun Jan 02 22:57:04 2011 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1458 +0,0 @@ - -@c ======================================================================== -@c Begin document body here -@c ======================================================================== - -@c ======================================================================== -@c PART: Building Topologies -@c ======================================================================== -@c The below chapters are under the major heading "Building Topologies" -@c This is similar to the Latex \part command -@c -@c ======================================================================== -@c Building Topologies -@c ======================================================================== -@node Building Topologies -@chapter Building Topologies - -@menu -* Building a Bus Network Topology:: -* Building a Wireless Network Topology:: -@end menu - -@c ======================================================================== -@c Building a Bus Network Topology -@c ======================================================================== -@node Building a Bus Network Topology -@section Building a Bus Network Topology - -@cindex topology -@cindex bus network topology -In this section we are going to expand our mastery of @command{ns-3} network -devices and channels to cover an example of a bus network. @command{Ns-3} -provides a net device and channel we call CSMA (Carrier Sense Multiple Access). - -The @command{ns-3} CSMA device models a simple network in the spirit of -Ethernet. A real Ethernet uses CSMA/CD (Carrier Sense Multiple Access with -Collision Detection) scheme with exponentially increasing backoff to contend -for the shared transmission medium. The @command{ns-3} CSMA device and -channel models only a subset of this. - -Just as we have seen point-to-point topology helper objects when constructing -point-to-point topologies, we will see equivalent CSMA topology helpers in -this section. The appearance and operation of these helpers should look -quite familiar to you. - -We provide an example script in our @code{examples/tutorial} directory. This script -builds on the @code{first.cc} script and adds a CSMA network to the -point-to-point simulation we've already considered. Go ahead and open -@code{examples/tutorial/second.cc} in your favorite editor. You will have already seen -enough @command{ns-3} code to understand most of what is going on in this -example, but we will go over the entire script and examine some of the output. - -Just as in the @code{first.cc} example (and in all ns-3 examples) the file -begins with an emacs mode line and some GPL boilerplate. - -The actual code begins by loading module include files just as was done in the -@code{first.cc} example. - -@verbatim - #include "ns3/core-module.h" - #include "ns3/simulator-module.h" - #include "ns3/node-module.h" - #include "ns3/helper-module.h" -@end verbatim - -One thing that can be surprisingly useful is a small bit of ASCII art that -shows a cartoon of the network topology constructed in the example. You will -find a similar ``drawing'' in most of our examples. - -In this case, you can see that we are going to extend our point-to-point -example (the link between the nodes n0 and n1 below) by hanging a bus network -off of the right side. Notice that this is the default network topology -since you can actually vary the number of nodes created on the LAN. If you -set nCsma to one, there will be a total of two nodes on the LAN (CSMA -channel) --- one required node and one ``extra'' node. By default there are -three ``extra'' nodes as seen below: - -@verbatim -// Default Network Topology -// -// 10.1.1.0 -// n0 -------------- n1 n2 n3 n4 -// point-to-point | | | | -// ================ -// LAN 10.1.2.0 -@end verbatim - -Then the ns-3 namespace is @code{used} and a logging component is defined. -This is all just as it was in @code{first.cc}, so there is nothing new yet. - -@verbatim - using namespace ns3; - - NS_LOG_COMPONENT_DEFINE ("SecondScriptExample"); -@end verbatim - -The main program begins with a slightly different twist. We use a verbose -flag to determine whether or not the @code{UdpEchoClientApplication} and -@code{UdpEchoServerApplication} logging components are enabled. This flag -defaults to true (the logging components are enabled) but allows us to turn -off logging during regression testing of this example. - -You will see some familiar code that will allow you to change the number -of devices on the CSMA network via command line argument. We did something -similar when we allowed the number of packets sent to be changed in the section -on command line arguments. The last line makes sure you have at least one -``extra'' node. - -The code consists of variations of previously covered API so you should be -entirely comfortable with the following code at this point in the tutorial. - -@verbatim - bool verbose = true; - uint32_t nCsma = 3; - - CommandLine cmd; - cmd.AddValue (``nCsma'', ``Number of \"extra\" CSMA nodes/devices'', nCsma); - cmd.AddValue (``verbose'', ``Tell echo applications to log if true'', verbose); - - cmd.Parse (argc,argv); - - if (verbose) - { - LogComponentEnable(``UdpEchoClientApplication'', LOG_LEVEL_INFO); - LogComponentEnable(``UdpEchoServerApplication'', LOG_LEVEL_INFO); - } - - nCsma = nCsma == 0 ? 1 : nCsma; -@end verbatim - -The next step is to create two nodes that we will connect via the -point-to-point link. The @code{NodeContainer} is used to do this just as was -done in @code{first.cc}. - -@verbatim - NodeContainer p2pNodes; - p2pNodes.Create (2); -@end verbatim - -Next, we declare another @code{NodeContainer} to hold the nodes that will be -part of the bus (CSMA) network. First, we just instantiate the container -object itself. - -@verbatim - NodeContainer csmaNodes; - csmaNodes.Add (p2pNodes.Get (1)); - csmaNodes.Create (nCsma); -@end verbatim - -The next line of code @code{Gets} the first node (as in having an index of one) -from the point-to-point node container and adds it to the container of nodes -that will get CSMA devices. The node in question is going to end up with a -point-to-point device @emph{and} a CSMA device. We then create a number of -``extra'' nodes that compose the remainder of the CSMA network. Since we -already have one node in the CSMA network -- the one that will have both a -point-to-point and CSMA net device, the number of ``extra'' nodes means the -number nodes you desire in the CSMA section minus one. - -The next bit of code should be quite familiar by now. We instantiate a -@code{PointToPointHelper} and set the associated default @code{Attributes} so -that we create a five megabit per second transmitter on devices created using -the helper and a two millisecond delay on channels created by the helper. - -@verbatim - PointToPointHelper pointToPoint; - pointToPoint.SetDeviceAttribute ("DataRate", StringValue ("5Mbps")); - pointToPoint.SetChannelAttribute ("Delay", StringValue ("2ms")); - - NetDeviceContainer p2pDevices; - p2pDevices = pointToPoint.Install (p2pNodes); -@end verbatim - -We then instantiate a @code{NetDeviceContainer} to keep track of the -point-to-point net devices and we @code{Install} devices on the -point-to-point nodes. - -We mentioned above that you were going to see a helper for CSMA devices and -channels, and the next lines introduce them. The @code{CsmaHelper} works just -like a @code{PointToPointHelper}, but it creates and connects CSMA devices and -channels. In the case of a CSMA device and channel pair, notice that the data -rate is specified by a @emph{channel} @code{Attribute} instead of a device -@code{Attribute}. This is because a real CSMA network does not allow one to mix, -for example, 10Base-T and 100Base-T devices on a given channel. We first set -the data rate to 100 megabits per second, and then set the speed-of-light delay -of the channel to 6560 nano-seconds (arbitrarily chosen as 1 nanosecond per foot -over a 100 meter segment). Notice that you can set an @code{Attribute} using -its native data type. - -@verbatim - CsmaHelper csma; - csma.SetChannelAttribute ("DataRate", StringValue ("100Mbps")); - csma.SetChannelAttribute ("Delay", TimeValue (NanoSeconds (6560))); - - NetDeviceContainer csmaDevices; - csmaDevices = csma.Install (csmaNodes); -@end verbatim - -Just as we created a @code{NetDeviceContainer} to hold the devices created by -the @code{PointToPointHelper} we create a @code{NetDeviceContainer} to hold -the devices created by our @code{CsmaHelper}. We call the @code{Install} -method of the @code{CsmaHelper} to install the devices into the nodes of the -@code{csmaNodes NodeContainer}. - -We now have our nodes, devices and channels created, but we have no protocol -stacks present. Just as in the @code{first.cc} script, we will use the -@code{InternetStackHelper} to install these stacks. - -@verbatim - InternetStackHelper stack; - stack.Install (p2pNodes.Get (0)); - stack.Install (csmaNodes); -@end verbatim - -Recall that we took one of the nodes from the @code{p2pNodes} container and -added it to the @code{csmaNodes} container. Thus we only need to install -the stacks on the remaining @code{p2pNodes} node, and all of the nodes in the -@code{csmaNodes} container to cover all of the nodes in the simulation. - -Just as in the @code{first.cc} example script, we are going to use the -@code{Ipv4AddressHelper} to assign IP addresses to our device interfaces. -First we use the network 10.1.1.0 to create the two addresses needed for our -two point-to-point devices. - -@verbatim - Ipv4AddressHelper address; - address.SetBase ("10.1.1.0", "255.255.255.0"); - Ipv4InterfaceContainer p2pInterfaces; - p2pInterfaces = address.Assign (p2pDevices); -@end verbatim - -Recall that we save the created interfaces in a container to make it easy to -pull out addressing information later for use in setting up the applications. - -We now need to assign IP addresses to our CSMA device interfaces. The -operation works just as it did for the point-to-point case, except we now -are performing the operation on a container that has a variable number of -CSMA devices --- remember we made the number of CSMA devices changeable by -command line argument. The CSMA devices will be associated with IP addresses -from network number 10.1.2.0 in this case, as seen below. - -@verbatim - address.SetBase ("10.1.2.0", "255.255.255.0"); - Ipv4InterfaceContainer csmaInterfaces; - csmaInterfaces = address.Assign (csmaDevices); -@end verbatim - -Now we have a topology built, but we need applications. This section is -going to be fundamentally similar to the applications section of -@code{first.cc} but we are going to instantiate the server on one of the -nodes that has a CSMA device and the client on the node having only a -point-to-point device. - -First, we set up the echo server. We create a @code{UdpEchoServerHelper} and -provide a required @code{Attribute} value to the constructor which is the server -port number. Recall that this port can be changed later using the -@code{SetAttribute} method if desired, but we require it to be provided to -the constructor. - -@verbatim - UdpEchoServerHelper echoServer (9); - - ApplicationContainer serverApps = echoServer.Install (csmaNodes.Get (nCsma)); - serverApps.Start (Seconds (1.0)); - serverApps.Stop (Seconds (10.0)); -@end verbatim - -Recall that the @code{csmaNodes NodeContainer} contains one of the -nodes created for the point-to-point network and @code{nCsma} ``extra'' nodes. -What we want to get at is the last of the ``extra'' nodes. The zeroth entry of -the @code{csmaNodes} container will be the point-to-point node. The easy -way to think of this, then, is if we create one ``extra'' CSMA node, then it -will be at index one of the @code{csmaNodes} container. By induction, -if we create @code{nCsma} ``extra'' nodes the last one will be at index -@code{nCsma}. You see this exhibited in the @code{Get} of the first line of -code. - -The client application is set up exactly as we did in the @code{first.cc} -example script. Again, we provide required @code{Attributes} to the -@code{UdpEchoClientHelper} in the constructor (in this case the remote address -and port). We tell the client to send packets to the server we just installed -on the last of the ``extra'' CSMA nodes. We install the client on the -leftmost point-to-point node seen in the topology illustration. - -@verbatim - UdpEchoClientHelper echoClient (csmaInterfaces.GetAddress (nCsma), 9); - echoClient.SetAttribute ("MaxPackets", UintegerValue (1)); - echoClient.SetAttribute ("Interval", TimeValue (Seconds (1.))); - echoClient.SetAttribute ("PacketSize", UintegerValue (1024)); - - ApplicationContainer clientApps = echoClient.Install (p2pNodes.Get (0)); - clientApps.Start (Seconds (2.0)); - clientApps.Stop (Seconds (10.0)); -@end verbatim - -Since we have actually built an internetwork here, we need some form of -internetwork routing. @command{ns-3} provides what we call global routing to -help you out. Global routing takes advantage of the fact that the entire -internetwork is accessible in the simulation and runs through the all of the -nodes created for the simulation --- it does the hard work of setting up routing -for you without having to configure routers. - -Basically, what happens is that each node behaves as if it were an OSPF router -that communicates instantly and magically with all other routers behind the -scenes. Each node generates link advertisements and communicates them -directly to a global route manager which uses this global information to -construct the routing tables for each node. Setting up this form of routing -is a one-liner: - -@verbatim - Ipv4GlobalRoutingHelper::PopulateRoutingTables (); -@end verbatim - -Next we enable pcap tracing. The first line of code to enable pcap tracing -in the point-to-point helper should be familiar to you by now. The second -line enables pcap tracing in the CSMA helper and there is an extra parameter -you haven't encountered yet. - -@verbatim - pointToPoint.EnablePcapAll ("second"); - csma.EnablePcap ("second", csmaDevices.Get (1), true); -@end verbatim - -The CSMA network is a multi-point-to-point network. This means that there -can (and are in this case) multiple endpoints on a shared medium. Each of -these endpoints has a net device associated with it. There are two basic -alternatives to gathering trace information from such a network. One way -is to create a trace file for each net device and store only the packets -that are emitted or consumed by that net device. Another way is to pick -one of the devices and place it in promiscuous mode. That single device -then ``sniffs'' the network for all packets and stores them in a single -pcap file. This is how @code{tcpdump}, for example, works. That final -parameter tells the CSMA helper whether or not to arrange to capture -packets in promiscuous mode. - -In this example, we are going to select one of the devices on the CSMA -network and ask it to perform a promiscuous sniff of the network, thereby -emulating what @code{tcpdump} would do. If you were on a Linux machine -you might do something like @code{tcpdump -i eth0} to get the trace. -In this case, we specify the device using @code{csmaDevices.Get(1)}, -which selects the first device in the container. Setting the final -parameter to true enables promiscuous captures. - -The last section of code just runs and cleans up the simulation just like -the @code{first.cc} example. - -@verbatim - Simulator::Run (); - Simulator::Destroy (); - return 0; - } -@end verbatim - -In order to run this example, copy the @code{second.cc} example script into -the scratch directory and use waf to build just as you did with -the @code{first.cc} example. If you are in the top-level directory of the -repository you just type, - -@verbatim - cp examples/tutorial/second.cc scratch/mysecond.cc - ./waf -@end verbatim - -Warning: We use the file @code{second.cc} as one of our regression tests to -verify that it works exactly as we think it should in order to make your -tutorial experience a positive one. This means that an executable named -@code{second} already exists in the project. To avoid any confusion -about what you are executing, please do the renaming to @code{mysecond.cc} -suggested above. - -If you are following the tutorial religiously (you are, aren't you) you will -still have the NS_LOG variable set, so go ahead and clear that variable and -run the program. - -@verbatim - export NS_LOG= - ./waf --run scratch/mysecond -@end verbatim - -Since we have set up the UDP echo applications to log just as we did in -@code{first.cc}, you will see similar output when you run the script. - -@verbatim - Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' - Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' - 'build' finished successfully (0.415s) - Sent 1024 bytes to 10.1.2.4 - Received 1024 bytes from 10.1.1.1 - Received 1024 bytes from 10.1.2.4 -@end verbatim - -Recall that the first message, ``@code{Sent 1024 bytes to 10.1.2.4},'' is the -UDP echo client sending a packet to the server. In this case, the server -is on a different network (10.1.2.0). The second message, ``@code{Received 1024 -bytes from 10.1.1.1},'' is from the UDP echo server, generated when it receives -the echo packet. The final message, ``@code{Received 1024 bytes from 10.1.2.4},'' -is from the echo client, indicating that it has received its echo back from -the server. - -If you now go and look in the top level directory, you will find three trace -files: - -@verbatim - second-0-0.pcap second-1-0.pcap second-2-0.pcap -@end verbatim - -Let's take a moment to look at the naming of these files. They all have the -same form, @code{--.pcap}. For example, the first file -in the listing is @code{second-0-0.pcap} which is the pcap trace from node -zero, device zero. This is the point-to-point net device on node zero. The -file @code{second-1-0.pcap} is the pcap trace for device zero on node one, -also a point-to-point net device; and the file @code{second-2-0.pcap} is the -pcap trace for device zero on node two. - -If you refer back to the topology illustration at the start of the section, -you will see that node zero is the leftmost node of the point-to-point link -and node one is the node that has both a point-to-point device and a CSMA -device. You will see that node two is the first ``extra'' node on the CSMA -network and its device zero was selected as the device to capture the -promiscuous-mode trace. - -Now, let's follow the echo packet through the internetwork. First, do a -tcpdump of the trace file for the leftmost point-to-point node --- node zero. - -@verbatim - tcpdump -nn -tt -r second-0-0.pcap -@end verbatim - -You should see the contents of the pcap file displayed: - -@verbatim - reading from file second-0-0.pcap, link-type PPP (PPP) - 2.000000 IP 10.1.1.1.49153 > 10.1.2.4.9: UDP, length 1024 - 2.007602 IP 10.1.2.4.9 > 10.1.1.1.49153: UDP, length 1024 -@end verbatim - -The first line of the dump indicates that the link type is PPP (point-to-point) -which we expect. You then see the echo packet leaving node zero via the -device associated with IP address 10.1.1.1 headed for IP address -10.1.2.4 (the rightmost CSMA node). This packet will move over the -point-to-point link and be received by the point-to-point net device on node -one. Let's take a look: - -@verbatim - tcpdump -nn -tt -r second-1-0.pcap -@end verbatim - -You should now see the pcap trace output of the other side of the point-to-point -link: - -@verbatim -reading from file second-1-0.pcap, link-type PPP (PPP) -2.003686 IP 10.1.1.1.49153 > 10.1.2.4.9: UDP, length 1024 -2.003915 IP 10.1.2.4.9 > 10.1.1.1.49153: UDP, length 1024 -@end verbatim - -Here we see that the link type is also PPP as we would expect. You see the -packet from IP address 10.1.1.1 (that was sent at 2.000000 seconds) headed -toward IP address 10.1.2.4 appear on this interface. Now, internally to this -node, the packet will be forwarded to the CSMA interface and we should see it -pop out on that device headed for its ultimate destination. - -Remember that we selected node 2 as the promiscuous sniffer node for the CSMA -network so let's then look at second-2-0.pcap and see if its there. - -@verbatim - tcpdump -nn -tt -r second-2-0.pcap -@end verbatim - -You should now see the promiscuous dump of node two, device zero: - -@verbatim - reading from file second-2-0.pcap, link-type EN10MB (Ethernet) - 2.003696 arp who-has 10.1.2.4 (ff:ff:ff:ff:ff:ff) tell 10.1.2.1 - 2.003707 arp reply 10.1.2.4 is-at 00:00:00:00:00:06 - 2.003801 IP 10.1.1.1.49153 > 10.1.2.4.9: UDP, length 1024 - 2.003811 arp who-has 10.1.2.1 (ff:ff:ff:ff:ff:ff) tell 10.1.2.4 - 2.003822 arp reply 10.1.2.1 is-at 00:00:00:00:00:03 - 2.003915 IP 10.1.2.4.9 > 10.1.1.1.49153: UDP, length 1024 -@end verbatim - -As you can see, the link type is now ``Ethernet''. Something new has appeared, -though. The bus network needs @code{ARP}, the Address Resolution Protocol. -Node one knows it needs to send the packet to IP address 10.1.2.4, but it -doesn't know the MAC address of the corresponding node. It broadcasts on the -CSMA network (ff:ff:ff:ff:ff:ff) asking for the device that has IP address -10.1.2.4. In this case, the rightmost node replies saying it is at MAC address -00:00:00:00:00:06. Note that node two is not directly involved in this -exchange, but is sniffing the network and reporting all of the traffic it sees. - -This exchange is seen in the following lines, - -@verbatim - 2.003696 arp who-has 10.1.2.4 (ff:ff:ff:ff:ff:ff) tell 10.1.2.1 - 2.003707 arp reply 10.1.2.4 is-at 00:00:00:00:00:06 -@end verbatim - -Then node one, device one goes ahead and sends the echo packet to the UDP echo -server at IP address 10.1.2.4. - -@verbatim - 2.003801 IP 10.1.1.1.49153 > 10.1.2.4.9: UDP, length 1024 -@end verbatim - -The server receives the echo request and turns the packet around trying to send -it back to the source. The server knows that this address is on another network -that it reaches via IP address 10.1.2.1. This is because we initialized global -routing and it has figured all of this out for us. But, the echo server node -doesn't know the MAC address of the first CSMA node, so it has to ARP for it -just like the first CSMA node had to do. - -@verbatim - 2.003811 arp who-has 10.1.2.1 (ff:ff:ff:ff:ff:ff) tell 10.1.2.4 - 2.003822 arp reply 10.1.2.1 is-at 00:00:00:00:00:03 -@end verbatim - -The server then sends the echo back to the forwarding node. - -@verbatim - 2.003915 IP 10.1.2.4.9 > 10.1.1.1.49153: UDP, length 1024 -@end verbatim - -Looking back at the rightmost node of the point-to-point link, - -@verbatim - tcpdump -nn -tt -r second-1-0.pcap -@end verbatim - -You can now see the echoed packet coming back onto the point-to-point link as -the last line of the trace dump. - -@verbatim -reading from file second-1-0.pcap, link-type PPP (PPP) -2.003686 IP 10.1.1.1.49153 > 10.1.2.4.9: UDP, length 1024 -2.003915 IP 10.1.2.4.9 > 10.1.1.1.49153: UDP, length 1024 -@end verbatim - -Lastly, you can look back at the node that originated the echo -@verbatim - tcpdump -nn -tt -r second-0-0.pcap -@end verbatim - -and see that the echoed packet arrives back at the source at 2.007602 seconds, - -@verbatim - reading from file second-0-0.pcap, link-type PPP (PPP) - 2.000000 IP 10.1.1.1.49153 > 10.1.2.4.9: UDP, length 1024 - 2.007602 IP 10.1.2.4.9 > 10.1.1.1.49153: UDP, length 1024 -@end verbatim - -Finally, recall that we added the ability to control the number of CSMA devices -in the simulation by command line argument. You can change this argument in -the same way as when we looked at changing the number of packets echoed in the -@code{first.cc} example. Try running the program with the number of ``extra'' -devices set to four: - -@verbatim - ./waf --run "scratch/mysecond --nCsma=4" -@end verbatim - -You should now see, - -@verbatim - Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' - Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' - 'build' finished successfully (0.405s) - Sent 1024 bytes to 10.1.2.5 - Received 1024 bytes from 10.1.1.1 - Received 1024 bytes from 10.1.2.5 -@end verbatim - -Notice that the echo server has now been relocated to the last of the CSMA -nodes, which is 10.1.2.5 instead of the default case, 10.1.2.4. - -It is possible that you may not be satisfied with a trace file generated by -a bystander in the CSMA network. You may really want to get a trace from -a single device and you may not be interested in any other traffic on the -network. You can do this fairly easily. - -Let's take a look at @code{scratch/mysecond.cc} and add that code enabling us -to be more specific. @code{ns-3} helpers provide methods that take a node -number and device number as parameters. Go ahead and replace the -@code{EnablePcap} calls with the calls below. - -@verbatim - pointToPoint.EnablePcap ("second", p2pNodes.Get (0)->GetId (), 0); - csma.EnablePcap ("second", csmaNodes.Get (nCsma)->GetId (), 0, false); - csma.EnablePcap ("second", csmaNodes.Get (nCsma-1)->GetId (), 0, false); -@end verbatim - -We know that we want to create a pcap file with the base name "second" and -we also know that the device of interest in both cases is going to be zero, -so those parameters are not really interesting. - -In order to get the node number, you have two choices: first, nodes are -numbered in a monotonically increasing fashion starting from zero in the -order in which you created them. One way to get a node number is to figure -this number out ``manually'' by contemplating the order of node creation. -If you take a look at the network topology illustration at the beginning of -the file, we did this for you and you can see that the last CSMA node is -going to be node number @code{nCsma + 1}. This approach can become -annoyingly difficult in larger simulations. - -An alternate way, which we use here, is to realize that the -@code{NodeContainers} contain pointers to @command{ns-3} @code{Node} Objects. -The @code{Node} Object has a method called @code{GetId} which will return that -node's ID, which is the node number we seek. Let's go take a look at the -Doxygen for the @code{Node} and locate that method, which is further down in -the @command{ns-3} core code than we've seen so far; but sometimes you have to -search diligently for useful things. - -Go to the Doxygen documentation for your release (recall that you can find it -on the project web site). You can get to the @code{Node} documentation by -looking through at the ``Classes'' tab and scrolling down the ``Class List'' -until you find @code{ns3::Node}. Select @code{ns3::Node} and you will be taken -to the documentation for the @code{Node} class. If you now scroll down to the -@code{GetId} method and select it, you will be taken to the detailed -documentation for the method. Using the @code{GetId} method can make -determining node numbers much easier in complex topologies. - -Let's clear the old trace files out of the top-level directory to avoid confusion -about what is going on, - -@verbatim - rm *.pcap - rm *.tr -@end verbatim - -If you build the new script and run the simulation setting @code{nCsma} to 100, - -@verbatim - ./waf --run "scratch/mysecond --nCsma=100" -@end verbatim - -you will see the following output: - -@verbatim - Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' - Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' - 'build' finished successfully (0.407s) - Sent 1024 bytes to 10.1.2.101 - Received 1024 bytes from 10.1.1.1 - Received 1024 bytes from 10.1.2.101 -@end verbatim - -Note that the echo server is now located at 10.1.2.101 which corresponds to -having 100 ``extra'' CSMA nodes with the echo server on the last one. If you -list the pcap files in the top level directory you will see, - -@verbatim - second-0-0.pcap second-100-0.pcap second-101-0.pcap -@end verbatim - -The trace file @code{second-0-0.pcap} is the ``leftmost'' point-to-point device -which is the echo packet source. The file @code{second-101-0.pcap} corresponds -to the rightmost CSMA device which is where the echo server resides. You may -have noticed that the final parameter on the call to enable pcap tracing on the -echo server node was false. This means that the trace gathered on that node -was in non-promiscuous mode. - -To illustrate the difference between promiscuous and non-promiscuous traces, we -also requested a non-promiscuous trace for the next-to-last node. Go ahead and -take a look at the @code{tcpdump} for @code{second-100-0.pcap}. - -@verbatim - tcpdump -nn -tt -r second-100-0.pcap -@end verbatim - -You can now see that node 100 is really a bystander in the echo exchange. The -only packets that it receives are the ARP requests which are broadcast to the -entire CSMA network. - -@verbatim - reading from file second-100-0.pcap, link-type EN10MB (Ethernet) - 2.003696 arp who-has 10.1.2.101 (ff:ff:ff:ff:ff:ff) tell 10.1.2.1 - 2.003811 arp who-has 10.1.2.1 (ff:ff:ff:ff:ff:ff) tell 10.1.2.101 -@end verbatim - -Now take a look at the @code{tcpdump} for @code{second-101-0.pcap}. - -@verbatim - tcpdump -nn -tt -r second-101-0.pcap -@end verbatim - -You can now see that node 101 is really the participant in the echo exchange. - -@verbatim - reading from file second-101-0.pcap, link-type EN10MB (Ethernet) - 2.003696 arp who-has 10.1.2.101 (ff:ff:ff:ff:ff:ff) tell 10.1.2.1 - 2.003696 arp reply 10.1.2.101 is-at 00:00:00:00:00:67 - 2.003801 IP 10.1.1.1.49153 > 10.1.2.101.9: UDP, length 1024 - 2.003801 arp who-has 10.1.2.1 (ff:ff:ff:ff:ff:ff) tell 10.1.2.101 - 2.003822 arp reply 10.1.2.1 is-at 00:00:00:00:00:03 - 2.003822 IP 10.1.2.101.9 > 10.1.1.1.49153: UDP, length 1024 -@end verbatim - -@c ======================================================================== -@c Models, Attributes and Reality -@c ======================================================================== -@node Models, Attributes and Reality -@section Models, Attributes and Reality - -This is a convenient place to make a small excursion and make an important -point. It may or may not be obvious to you, but whenever one is using a -simulation, it is important to understand exactly what is being modeled and -what is not. It is tempting, for example, to think of the CSMA devices -and channels used in the previous section as if they were real Ethernet -devices; and to expect a simulation result to directly reflect what will -happen in a real Ethernet. This is not the case. - -A model is, by definition, an abstraction of reality. It is ultimately the -responsibility of the simulation script author to determine the so-called -``range of accuracy'' and ``domain of applicability'' of the simulation as -a whole, and therefore its constituent parts. - -In some cases, like @code{Csma}, it can be fairly easy to determine what is -@emph{not} modeled. By reading the model description (@code{csma.h}) you -can find that there is no collision detection in the CSMA model and decide -on how applicable its use will be in your simulation or what caveats you -may want to include with your results. In other cases, it can be quite easy -to configure behaviors that might not agree with any reality you can go out -and buy. It will prove worthwhile to spend some time investigating a few -such instances, and how easily you can swerve outside the bounds of reality -in your simulations. - -As you have seen, @command{ns-3} provides @code{Attributes} which a user -can easily set to change model behavior. Consider two of the @code{Attributes} -of the @code{CsmaNetDevice}: @code{Mtu} and @code{EncapsulationMode}. -The @code{Mtu} attribute indicates the Maximum Transmission Unit to the -device. This is the size of the largest Protocol Data Unit (PDU) that the -device can send. - -The MTU defaults to 1500 bytes in the @code{CsmaNetDevice}. This default -corresponds to a number found in RFC 894, ``A Standard for the Transmission -of IP Datagrams over Ethernet Networks.'' The number is actually derived -from the maximum packet size for 10Base5 (full-spec Ethernet) networks -- -1518 bytes. If you subtract the DIX encapsulation overhead for Ethernet -packets (18 bytes) you will end up with a maximum possible data size (MTU) -of 1500 bytes. One can also find that the @code{MTU} for IEEE 802.3 networks -is 1492 bytes. This is because LLC/SNAP encapsulation adds an extra eight -bytes of overhead to the packet. In both cases, the underlying hardware can -only send 1518 bytes, but the data size is different. - -In order to set the encapsulation mode, the @code{CsmaNetDevice} provides -an @code{Attribute} called @code{EncapsulationMode} which can take on the -values @code{Dix} or @code{Llc}. These correspond to Ethernet and LLC/SNAP -framing respectively. - -If one leaves the @code{Mtu} at 1500 bytes and changes the encapsulation mode -to @code{Llc}, the result will be a network that encapsulates 1500 byte PDUs -with LLC/SNAP framing resulting in packets of 1526 bytes, which would be -illegal in many networks, since they can transmit a maximum of 1518 bytes per -packet. This would most likely result in a simulation that quite subtly does -not reflect the reality you might be expecting. - -Just to complicate the picture, there exist jumbo frames (1500 < MTU <= 9000 bytes) -and super-jumbo (MTU > 9000 bytes) frames that are not officially sanctioned -by IEEE but are available in some high-speed (Gigabit) networks and NICs. One -could leave the encapsulation mode set to @code{Dix}, and set the @code{Mtu} -@code{Attribute} on a @code{CsmaNetDevice} to 64000 bytes -- even though an -associated @code{CsmaChannel DataRate} was set at 10 megabits per second. -This would essentially model an Ethernet switch made out of vampire-tapped -1980s-style 10Base5 networks that support super-jumbo datagrams. This is -certainly not something that was ever made, nor is likely to ever be made, -but it is quite easy for you to configure. - -In the previous example, you used the command line to create a simulation that -had 100 @code{Csma} nodes. You could have just as easily created a simulation -with 500 nodes. If you were actually modeling that 10Base5 vampire-tap network, -the maximum length of a full-spec Ethernet cable is 500 meters, with a minimum -tap spacing of 2.5 meters. That means there could only be 200 taps on a -real network. You could have quite easily built an illegal network in that -way as well. This may or may not result in a meaningful simulation depending -on what you are trying to model. - -Similar situations can occur in many places in @command{ns-3} and in any -simulator. For example, you may be able to position nodes in such a way that -they occupy the same space at the same time, or you may be able to configure -amplifiers or noise levels that violate the basic laws of physics. - -@command{ns-3} generally favors flexibility, and many models will allow freely -setting @code{Attributes} without trying to enforce any arbitrary consistency -or particular underlying spec. - -The thing to take home from this is that @command{ns-3} is going to provide a -super-flexible base for you to experiment with. It is up to you to understand -what you are asking the system to do and to make sure that the simulations you -create have some meaning and some connection with a reality defined by you. - -@c ======================================================================== -@c Building a Wireless Network Topology -@c ======================================================================== -@node Building a Wireless Network Topology -@section Building a Wireless Network Topology - -@cindex topology -@cindex wireless network topology -In this section we are going to further expand our knowledge of @command{ns-3} -network devices and channels to cover an example of a wireless network. -@command{Ns-3} provides a set of 802.11 models that attempt to provide an -accurate MAC-level implementation of the 802.11 specification and a -``not-so-slow'' PHY-level model of the 802.11a specification. - -Just as we have seen both point-to-point and CSMA topology helper objects when -constructing point-to-point topologies, we will see equivalent @code{Wifi} -topology helpers in this section. The appearance and operation of these -helpers should look quite familiar to you. - -We provide an example script in our @code{examples/tutorial} directory. This script -builds on the @code{second.cc} script and adds a Wifi network. Go ahead and -open @code{examples/tutorial/third.cc} in your favorite editor. You will have already -seen enough @command{ns-3} code to understand most of what is going on in -this example, but there are a few new things, so we will go over the entire -script and examine some of the output. - -Just as in the @code{second.cc} example (and in all @command{ns-3} examples) -the file begins with an emacs mode line and some GPL boilerplate. - -Take a look at the ASCII art (reproduced below) that shows the default network -topology constructed in the example. You can see that we are going to -further extend our example by hanging a wireless network off of the left side. -Notice that this is a default network topology since you can actually vary the -number of nodes created on the wired and wireless networks. Just as in the -@code{second.cc} script case, if you change @code{nCsma}, it will give you a -number of ``extra'' CSMA nodes. Similarly, you can set @code{nWifi} to -control how many @code{STA} (station) nodes are created in the simulation. -There will always be one @code{AP} (access point) node on the wireless -network. By default there are three ``extra'' CSMA nodes and three wireless -@code{STA} nodes. - -The code begins by loading module include files just as was done in the -@code{second.cc} example. There are a couple of new includes corresponding -to the Wifi module and the mobility module which we will discuss below. - -@verbatim -#include "ns3/core-module.h" -#include "ns3/simulator-module.h" -#include "ns3/node-module.h" -#include "ns3/helper-module.h" -#include "ns3/wifi-module.h" -#include "ns3/mobility-module.h" -@end verbatim - -The network topology illustration follows: - -@verbatim - // Default Network Topology - // - // Wifi 10.1.3.0 - // AP - // * * * * - // | | | | 10.1.1.0 - // n5 n6 n7 n0 -------------- n1 n2 n3 n4 - // point-to-point | | | | - // ================ - // LAN 10.1.2.0 -@end verbatim - -You can see that we are adding a new network device to the node on the left -side of the point-to-point link that becomes the access point for the wireless -network. A number of wireless STA nodes are created to fill out the new -10.1.3.0 network as shown on the left side of the illustration. - -After the illustration, the @code{ns-3} namespace is @code{used} and a logging -component is defined. This should all be quite familiar by now. - -@verbatim - using namespace ns3; - - NS_LOG_COMPONENT_DEFINE ("ThirdScriptExample"); -@end verbatim - -The main program begins just like @code{second.cc} by adding some command line -parameters for enabling or disabling logging components and for changing the -number of devices created. - -@verbatim - bool verbose = true; - uint32_t nCsma = 3; - uint32_t nWifi = 3; - - CommandLine cmd; - cmd.AddValue (``nCsma'', ``Number of \"extra\" CSMA nodes/devices'', nCsma); - cmd.AddValue (``nWifi'', ``Number of wifi STA devices'', nWifi); - cmd.AddValue (``verbose'', ``Tell echo applications to log if true'', verbose); - - cmd.Parse (argc,argv); - - if (verbose) - { - LogComponentEnable(``UdpEchoClientApplication'', LOG_LEVEL_INFO); - LogComponentEnable(``UdpEchoServerApplication'', LOG_LEVEL_INFO); - } -@end verbatim - -Just as in all of the previous examples, the next step is to create two nodes -that we will connect via the point-to-point link. - -@verbatim - NodeContainer p2pNodes; - p2pNodes.Create (2); -@end verbatim - -Next, we see an old friend. We instantiate a @code{PointToPointHelper} and -set the associated default @code{Attributes} so that we create a five megabit -per second transmitter on devices created using the helper and a two millisecond -delay on channels created by the helper. We then @code{Intall} the devices -on the nodes and the channel between them. - -@verbatim - PointToPointHelper pointToPoint; - pointToPoint.SetDeviceAttribute ("DataRate", StringValue ("5Mbps")); - pointToPoint.SetChannelAttribute ("Delay", StringValue ("2ms")); - - NetDeviceContainer p2pDevices; - p2pDevices = pointToPoint.Install (p2pNodes); -@end verbatim - -Next, we declare another @code{NodeContainer} to hold the nodes that will be -part of the bus (CSMA) network. - -@verbatim - NodeContainer csmaNodes; - csmaNodes.Add (p2pNodes.Get (1)); - csmaNodes.Create (nCsma); -@end verbatim - -The next line of code @code{Gets} the first node (as in having an index of one) -from the point-to-point node container and adds it to the container of nodes -that will get CSMA devices. The node in question is going to end up with a -point-to-point device and a CSMA device. We then create a number of ``extra'' -nodes that compose the remainder of the CSMA network. - -We then instantiate a @code{CsmaHelper} and set its @code{Attributes} as we did -in the previous example. We create a @code{NetDeviceContainer} to keep track of -the created CSMA net devices and then we @code{Install} CSMA devices on the -selected nodes. - -@verbatim - CsmaHelper csma; - csma.SetChannelAttribute ("DataRate", StringValue ("100Mbps")); - csma.SetChannelAttribute ("Delay", TimeValue (NanoSeconds (6560))); - - NetDeviceContainer csmaDevices; - csmaDevices = csma.Install (csmaNodes); -@end verbatim - -Next, we are going to create the nodes that will be part of the Wifi network. -We are going to create a number of ``station'' nodes as specified by the -command line argument, and we are going to use the ``leftmost'' node of the -point-to-point link as the node for the access point. - -@verbatim - NodeContainer wifiStaNodes; - wifiStaNodes.Create (nWifi); - NodeContainer wifiApNode = p2pNodes.Get (0); -@end verbatim - -The next bit of code constructs the wifi devices and the interconnection -channel between these wifi nodes. First, we configure the PHY and channel -helpers: - -@verbatim - YansWifiChannelHelper channel = YansWifiChannelHelper::Default (); - YansWifiPhyHelper phy = YansWifiPhyHelper::Default (); -@end verbatim - -For simplicity, this code uses the default PHY layer configuration and -channel models which are documented in the API doxygen documentation for -the @code{YansWifiChannelHelper::Default} and @code{YansWifiPhyHelper::Default} -methods. Once these objects are created, we create a channel object -and associate it to our PHY layer object manager to make sure -that all the PHY layer objects created by the @code{YansWifiPhyHelper} -share the same underlying channel, that is, they share the same -wireless medium and can communication and interfere: - -@verbatim - phy.SetChannel (channel.Create ()); -@end verbatim - -Once the PHY helper is configured, we can focus on the MAC layer. Here we choose to -work with non-Qos MACs so we use a NqosWifiMacHelper object to set MAC parameters. - -@verbatim - WifiHelper wifi = WifiHelper::Default (); - wifi.SetRemoteStationManager ("ns3::AarfWifiManager"); - - NqosWifiMacHelper mac = NqosWifiMacHelper::Default (); -@end verbatim - -The @code{SetRemoteStationManager} method tells the helper the type of -rate control algorithm to use. Here, it is asking the helper to use the AARF -algorithm --- details are, of course, available in Doxygen. - -Next, we configure the type of MAC, the SSID of the infrastructure network we -want to setup and make sure that our stations don't perform active probing: - -@verbatim - Ssid ssid = Ssid ("ns-3-ssid"); - mac.SetType ("ns3::StaWifiMac", - "Ssid", SsidValue (ssid), - "ActiveProbing", BooleanValue (false)); -@end verbatim - -This code first creates an 802.11 service set identifier (SSID) object -that will be used to set the value of the ``Ssid'' @code{Attribute} of -the MAC layer implementation. The particular kind of MAC layer that -will be created by the helper is specified by @code{Attribute} as -being of the "ns3::StaWifiMac" type. The use of -@code{NqosWifiMacHelper} will ensure that the ''QosSupported'' -@code{Attribute} for created MAC objects is set false. The combination -of these two configurations means that the MAC instance next created -will be a non-QoS non-AP station (STA) in an infrastructure BSS (i.e., -a BSS with an AP). Finally, the ``ActiveProbing'' @code{Attribute} is -set to false. This means that probe requests will not be sent by MACs -created by this helper. - -Once all the station-specific parameters are fully configured, both at the -MAC and PHY layers, we can invoke our now-familiar @code{Install} method to -create the wifi devices of these stations: - -@verbatim - NetDeviceContainer staDevices; - staDevices = wifi.Install (phy, mac, wifiStaNodes); -@end verbatim - -We have configured Wifi for all of our STA nodes, and now we need to -configure the AP (access point) node. We begin this process by changing -the default @code{Attributes} of the @code{NqosWifiMacHelper} to reflect the -requirements of the AP. - -@verbatim - mac.SetType ("ns3::ApWifiMac", - "Ssid", SsidValue (ssid), - "BeaconGeneration", BooleanValue (true), - "BeaconInterval", TimeValue (Seconds (2.5))); -@end verbatim - -In this case, the @code{NqosWifiMacHelper} is going to create MAC -layers of the ``ns3::ApWifiMac'', the latter specifying that a MAC -instance configured as an AP should be created, with the helper type -implying that the ''QosSupported'' @code{Attribute} should be set to -false - disabling 802.11e/WMM-style QoS support at created APs. We -set the ``BeaconGeneration'' @code{Attribute} to true and also set an -interval between beacons of 2.5 seconds. - -The next lines create the single AP which shares the same set of PHY-level -@code{Attributes} (and channel) as the stations: - -@verbatim - NetDeviceContainer apDevices; - apDevices = wifi.Install (phy, mac, wifiApNode); -@end verbatim - -Now, we are going to add mobility models. We want the STA nodes to be mobile, -wandering around inside a bounding box, and we want to make the AP node -stationary. We use the @code{MobilityHelper} to make this easy for us. -First, we instantiate a @code{MobilityHelper} object and set some -@code{Attributes} controlling the ``position allocator'' functionality. - -@verbatim - MobilityHelper mobility; - - mobility.SetPositionAllocator ("ns3::GridPositionAllocator", - "MinX", DoubleValue (0.0), - "MinY", DoubleValue (0.0), - "DeltaX", DoubleValue (5.0), - "DeltaY", DoubleValue (10.0), - "GridWidth", UintegerValue (3), - "LayoutType", StringValue ("RowFirst")); -@end verbatim - -This code tells the mobility helper to use a two-dimensional grid to initially -place the STA nodes. Feel free to explore the Doxygen for class -@code{ns3::GridPositionAllocator} to see exactly what is being done. - -We have arranged our nodes on an initial grid, but now we need to tell them -how to move. We choose the @code{RandomWalk2dMobilityModel} which has the -nodes move in a random direction at a random speed around inside a bounding -box. - -@verbatim - mobility.SetMobilityModel ("ns3::RandomWalk2dMobilityModel", - "Bounds", RectangleValue (Rectangle (-50, 50, -50, 50))); -@end verbatim - -We now tell the @code{MobilityHelper} to install the mobility models on the -STA nodes. - -@verbatim - mobility.Install (wifiStaNodes); -@end verbatim - -We want the access point to remain in a fixed position during the simulation. -We accomplish this by setting the mobility model for this node to be the -@code{ns3::ConstantPositionMobilityModel}: - -@verbatim - mobility.SetMobilityModel ("ns3::ConstantPositionMobilityModel"); - mobility.Install (wifiApNode); -@end verbatim - -We now have our nodes, devices and channels created, and mobility models -chosen for the Wifi nodes, but we have no protocol stacks present. Just as -we have done previously many times, we will use the @code{InternetStackHelper} -to install these stacks. - -@verbatim - InternetStackHelper stack; - stack.Install (csmaNodes); - stack.Install (wifiApNode); - stack.Install (wifiStaNodes); -@end verbatim - -Just as in the @code{second.cc} example script, we are going to use the -@code{Ipv4AddressHelper} to assign IP addresses to our device interfaces. -First we use the network 10.1.1.0 to create the two addresses needed for our -two point-to-point devices. Then we use network 10.1.2.0 to assign addresses -to the CSMA network and then we assign addresses from network 10.1.3.0 to -both the STA devices and the AP on the wireless network. - -@verbatim - Ipv4AddressHelper address; - - address.SetBase ("10.1.1.0", "255.255.255.0"); - Ipv4InterfaceContainer p2pInterfaces; - p2pInterfaces = address.Assign (p2pDevices); - - address.SetBase ("10.1.2.0", "255.255.255.0"); - Ipv4InterfaceContainer csmaInterfaces; - csmaInterfaces = address.Assign (csmaDevices); - - address.SetBase ("10.1.3.0", "255.255.255.0"); - address.Assign (staDevices); - address.Assign (apDevices); -@end verbatim - -We put the echo server on the ``rightmost'' node in the illustration at the -start of the file. We have done this before. - -@verbatim - UdpEchoServerHelper echoServer (9); - - ApplicationContainer serverApps = echoServer.Install (csmaNodes.Get (nCsma)); - serverApps.Start (Seconds (1.0)); - serverApps.Stop (Seconds (10.0)); -@end verbatim - -And we put the echo client on the last STA node we created, pointing it to -the server on the CSMA network. We have also seen similar operations before. - -@verbatim - UdpEchoClientHelper echoClient (csmaInterfaces.GetAddress (nCsma), 9); - echoClient.SetAttribute ("MaxPackets", UintegerValue (1)); - echoClient.SetAttribute ("Interval", TimeValue (Seconds (1.))); - echoClient.SetAttribute ("PacketSize", UintegerValue (1024)); - - ApplicationContainer clientApps = - echoClient.Install (wifiStaNodes.Get (nWifi - 1)); - clientApps.Start (Seconds (2.0)); - clientApps.Stop (Seconds (10.0)); -@end verbatim - -Since we have built an internetwork here, we need to enable internetwork routing -just as we did in the @code{second.cc} example script. - -@verbatim - Ipv4GlobalRoutingHelper::PopulateRoutingTables (); -@end verbatim - -One thing that can surprise some users is the fact that the simulation we just -created will never ``naturally'' stop. This is because we asked the wireless -access point to generate beacons. It will generate beacons forever, and this -will result in simulator events being scheduled into the future indefinitely, -so we must tell the simulator to stop even though it may have beacon generation -events scheduled. The following line of code tells the simulator to stop so that -we don't simulate beacons forever and enter what is essentially an endless -loop. - -@verbatim - Simulator::Stop (Seconds (10.0)); -@end verbatim - -We create just enough tracing to cover all three networks: - -@verbatim - pointToPoint.EnablePcapAll ("third"); - phy.EnablePcap ("third", apDevices.Get (0)); - csma.EnablePcap ("third", csmaDevices.Get (0), true); -@end verbatim - -These three lines of code will start pcap tracing on both of the point-to-point -nodes that serves as our backbone, will start a promiscuous (monitor) mode -trace on the Wifi network, and will start a promiscuous trace on the CSMA -network. This will let us see all of the traffic with a minimum number of -trace files. - -Finally, we actually run the simulation, clean up and then exit the program. - -@verbatim - Simulator::Run (); - Simulator::Destroy (); - return 0; - } -@end verbatim - -In order to run this example, you have to copy the @code{third.cc} example -script into the scratch directory and use Waf to build just as you did with -the @code{second.cc} example. If you are in the top-level directory of the -repository you would type, - -@verbatim - cp examples/third.cc scratch/mythird.cc - ./waf - ./waf --run scratch/mythird -@end verbatim - -Again, since we have set up the UDP echo applications just as we did in the -@code{second.cc} script, you will see similar output. - -@verbatim - Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' - Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' - 'build' finished successfully (0.407s) - Sent 1024 bytes to 10.1.2.4 - Received 1024 bytes from 10.1.3.3 - Received 1024 bytes from 10.1.2.4 -@end verbatim - -Recall that the first message, ``@code{Sent 1024 bytes to 10.1.2.4},'' is the -UDP echo client sending a packet to the server. In this case, the client -is on the wireless network (10.1.3.0). The second message, -``@code{Received 1024 bytes from 10.1.3.3},'' is from the UDP echo server, -generated when it receives the echo packet. The final message, -``@code{Received 1024 bytes from 10.1.2.4},'' is from the echo client, indicating -that it has received its echo back from the server. - -If you now go and look in the top level directory, you will find four trace -files from this simulation, two from node zero and two from node one: - -@verbatim -third-0-0.pcap third-0-1.pcap third-1-0.pcap third-1-1.pcap -@end verbatim - -The file ``third-0-0.pcap'' corresponds to the point-to-point device on node -zero -- the left side of the ``backbone''. The file ``third-1-0.pcap'' -corresponds to the point-to-point device on node one -- the right side of the -``backbone''. The file ``third-0-1.pcap'' will be the promiscuous (monitor -mode) trace from the Wifi network and the file ``third-1-1.pcap'' will be the -promiscuous trace from the CSMA network. Can you verify this by inspecting -the code? - -Since the echo client is on the Wifi network, let's start there. Let's take -a look at the promiscuous (monitor mode) trace we captured on that network. - -@verbatim - tcpdump -nn -tt -r third-0-1.pcap -@end verbatim - -You should see some wifi-looking contents you haven't seen here before: - -@verbatim - reading from file third-0-1.pcap, link-type IEEE802_11 (802.11) - 0.000025 Beacon () [6.0* 9.0 12.0 18.0 24.0 36.0 48.0 54.0 Mbit] IBSS - 0.000263 Assoc Request () [6.0 9.0 12.0 18.0 24.0 36.0 48.0 54.0 Mbit] - 0.000279 Acknowledgment RA:00:00:00:00:00:07 - 0.000357 Assoc Response AID(0) :: Succesful - 0.000501 Acknowledgment RA:00:00:00:00:00:0a - 0.000748 Assoc Request () [6.0 9.0 12.0 18.0 24.0 36.0 48.0 54.0 Mbit] - 0.000764 Acknowledgment RA:00:00:00:00:00:08 - 0.000842 Assoc Response AID(0) :: Succesful - 0.000986 Acknowledgment RA:00:00:00:00:00:0a - 0.001242 Assoc Request () [6.0 9.0 12.0 18.0 24.0 36.0 48.0 54.0 Mbit] - 0.001258 Acknowledgment RA:00:00:00:00:00:09 - 0.001336 Assoc Response AID(0) :: Succesful - 0.001480 Acknowledgment RA:00:00:00:00:00:0a - 2.000112 arp who-has 10.1.3.4 (ff:ff:ff:ff:ff:ff) tell 10.1.3.3 - 2.000128 Acknowledgment RA:00:00:00:00:00:09 - 2.000206 arp who-has 10.1.3.4 (ff:ff:ff:ff:ff:ff) tell 10.1.3.3 - 2.000487 arp reply 10.1.3.4 is-at 00:00:00:00:00:0a - 2.000659 Acknowledgment RA:00:00:00:00:00:0a - 2.002169 IP 10.1.3.3.49153 > 10.1.2.4.9: UDP, length 1024 - 2.002185 Acknowledgment RA:00:00:00:00:00:09 - 2.009771 arp who-has 10.1.3.3 (ff:ff:ff:ff:ff:ff) tell 10.1.3.4 - 2.010029 arp reply 10.1.3.3 is-at 00:00:00:00:00:09 - 2.010045 Acknowledgment RA:00:00:00:00:00:09 - 2.010231 IP 10.1.2.4.9 > 10.1.3.3.49153: UDP, length 1024 - 2.011767 Acknowledgment RA:00:00:00:00:00:0a - 2.500000 Beacon () [6.0* 9.0 12.0 18.0 24.0 36.0 48.0 54.0 Mbit] IBSS - 5.000000 Beacon () [6.0* 9.0 12.0 18.0 24.0 36.0 48.0 54.0 Mbit] IBSS - 7.500000 Beacon () [6.0* 9.0 12.0 18.0 24.0 36.0 48.0 54.0 Mbit] IBSS -@end verbatim - -You can see that the link type is now 802.11 as you would expect. You can -probably understand what is going on and find the IP echo request and response -packets in this trace. We leave it as an exercise to completely parse the -trace dump. - -Now, look at the pcap file of the right side of the point-to-point link, - -@verbatim - tcpdump -nn -tt -r third-0-0.pcap -@end verbatim - -Again, you should see some familiar looking contents: - -@verbatim - reading from file third-0-0.pcap, link-type PPP (PPP) - 2.002169 IP 10.1.3.3.49153 > 10.1.2.4.9: UDP, length 1024 - 2.009771 IP 10.1.2.4.9 > 10.1.3.3.49153: UDP, length 1024 -@end verbatim - -This is the echo packet going from left to right (from Wifi to CSMA) and back -again across the point-to-point link. - -Now, look at the pcap file of the right side of the point-to-point link, - -@verbatim - tcpdump -nn -tt -r third-1-0.pcap -@end verbatim - -Again, you should see some familiar looking contents: - -@verbatim - reading from file third-1-0.pcap, link-type PPP (PPP) - 2.005855 IP 10.1.3.3.49153 > 10.1.2.4.9: UDP, length 1024 - 2.006084 IP 10.1.2.4.9 > 10.1.3.3.49153: UDP, length 1024 -@end verbatim - -This is also the echo packet going from left to right (from Wifi to CSMA) and -back again across the point-to-point link with slightly different timings -as you might expect. - -The echo server is on the CSMA network, let's look at the promiscuous trace -there: - -@verbatim - tcpdump -nn -tt -r third-1-1.pcap -@end verbatim - -You should see some familiar looking contents: - -@verbatim - reading from file third-1-1.pcap, link-type EN10MB (Ethernet) - 2.005855 arp who-has 10.1.2.4 (ff:ff:ff:ff:ff:ff) tell 10.1.2.1 - 2.005877 arp reply 10.1.2.4 is-at 00:00:00:00:00:06 - 2.005877 IP 10.1.3.3.49153 > 10.1.2.4.9: UDP, length 1024 - 2.005980 arp who-has 10.1.2.1 (ff:ff:ff:ff:ff:ff) tell 10.1.2.4 - 2.005980 arp reply 10.1.2.1 is-at 00:00:00:00:00:03 - 2.006084 IP 10.1.2.4.9 > 10.1.3.3.49153: UDP, length 1024 -@end verbatim - -This should be easily understood. If you've forgotten, go back and look at -the discussion in @code{second.cc}. This is the same sequence. - -Now, we spent a lot of time setting up mobility models for the wireless network -and so it would be a shame to finish up without even showing that the STA -nodes are actually moving around during the simulation. Let's do this by hooking -into the @code{MobilityModel} course change trace source. This is just a sneak -peek into the detailed tracing section which is coming up, but this seems a very -nice place to get an example in. - -As mentioned in the ``Tweaking ns-3'' section, the @command{ns-3} tracing system -is divided into trace sources and trace sinks, and we provide functions to -connect the two. We will use the mobility model predefined course change -trace source to originate the trace events. We will need to write a trace -sink to connect to that source that will display some pretty information for -us. Despite its reputation as being difficult, it's really quite simple. -Just before the main program of the @code{scratch/mythird.cc} script, add the -following function: - -@verbatim - void - CourseChange (std::string context, Ptr model) - { - Vector position = model->GetPosition (); - NS_LOG_UNCOND (context << - " x = " << position.x << ", y = " << position.y); - } -@end verbatim - -This code just pulls the position information from the mobility model and -unconditionally logs the x and y position of the node. We are -going to arrange for this function to be called every time the wireless -node with the echo client changes its position. We do this using the -@code{Config::Connect} function. Add the following lines of code to the -script just before the @code{Simulator::Run} call. - -@verbatim - std::ostringstream oss; - oss << - "/NodeList/" << wifiStaNodes.Get (nWifi - 1)->GetId () << - "/$ns3::MobilityModel/CourseChange"; - - Config::Connect (oss.str (), MakeCallback (&CourseChange)); -@end verbatim - -What we do here is to create a string containing the tracing namespace path -of the event to which we want to connect. First, we have to figure out which -node it is we want using the @code{GetId} method as described earlier. In the -case of the default number of CSMA and wireless nodes, this turns out to be -node seven and the tracing namespace path to the mobility model would look -like, - -@verbatim - /NodeList/7/$ns3::MobilityModel/CourseChange -@end verbatim - -Based on the discussion in the tracing section, you may infer that this trace -path references the seventh node in the global NodeList. It specifies -what is called an aggregated object of type @code{ns3::MobilityModel}. The -dollar sign prefix implies that the MobilityModel is aggregated to node seven. -The last component of the path means that we are hooking into the -``CourseChange'' event of that model. - -We make a connection between the trace source in node seven with our trace -sink by calling @code{Config::Connect} and passing this namespace path. Once -this is done, every course change event on node seven will be hooked into our -trace sink, which will in turn print out the new position. - -If you now run the simulation, you will see the course changes displayed as -they happen. - -@verbatim - Build finished successfully (00:00:01) - /NodeList/7/$ns3::MobilityModel/CourseChange x = 10, y = 0 - /NodeList/7/$ns3::MobilityModel/CourseChange x = 9.41539, y = -0.811313 - /NodeList/7/$ns3::MobilityModel/CourseChange x = 8.46199, y = -1.11303 - /NodeList/7/$ns3::MobilityModel/CourseChange x = 7.52738, y = -1.46869 - /NodeList/7/$ns3::MobilityModel/CourseChange x = 6.67099, y = -1.98503 - /NodeList/7/$ns3::MobilityModel/CourseChange x = 5.6835, y = -2.14268 - /NodeList/7/$ns3::MobilityModel/CourseChange x = 4.70932, y = -1.91689 - Sent 1024 bytes to 10.1.2.4 - Received 1024 bytes from 10.1.3.3 - Received 1024 bytes from 10.1.2.4 - /NodeList/7/$ns3::MobilityModel/CourseChange x = 5.53175, y = -2.48576 - /NodeList/7/$ns3::MobilityModel/CourseChange x = 4.58021, y = -2.17821 - /NodeList/7/$ns3::MobilityModel/CourseChange x = 4.18915, y = -1.25785 - /NodeList/7/$ns3::MobilityModel/CourseChange x = 4.7572, y = -0.434856 - /NodeList/7/$ns3::MobilityModel/CourseChange x = 4.62404, y = 0.556238 - /NodeList/7/$ns3::MobilityModel/CourseChange x = 4.74127, y = 1.54934 - /NodeList/7/$ns3::MobilityModel/CourseChange x = 5.73934, y = 1.48729 - /NodeList/7/$ns3::MobilityModel/CourseChange x = 6.18521, y = 0.59219 - /NodeList/7/$ns3::MobilityModel/CourseChange x = 6.58121, y = 1.51044 - /NodeList/7/$ns3::MobilityModel/CourseChange x = 7.27897, y = 2.22677 - /NodeList/7/$ns3::MobilityModel/CourseChange x = 6.42888, y = 1.70014 - /NodeList/7/$ns3::MobilityModel/CourseChange x = 7.40519, y = 1.91654 - /NodeList/7/$ns3::MobilityModel/CourseChange x = 6.51981, y = 1.45166 - /NodeList/7/$ns3::MobilityModel/CourseChange x = 7.34588, y = 2.01523 - /NodeList/7/$ns3::MobilityModel/CourseChange x = 7.81046, y = 2.90077 - /NodeList/7/$ns3::MobilityModel/CourseChange x = 6.89186, y = 3.29596 - /NodeList/7/$ns3::MobilityModel/CourseChange x = 7.46617, y = 2.47732 - /NodeList/7/$ns3::MobilityModel/CourseChange x = 7.05492, y = 1.56579 - /NodeList/7/$ns3::MobilityModel/CourseChange x = 8.00393, y = 1.25054 - /NodeList/7/$ns3::MobilityModel/CourseChange x = 7.00968, y = 1.35768 - /NodeList/7/$ns3::MobilityModel/CourseChange x = 7.33503, y = 2.30328 - /NodeList/7/$ns3::MobilityModel/CourseChange x = 7.18682, y = 3.29223 - /NodeList/7/$ns3::MobilityModel/CourseChange x = 7.96865, y = 2.66873 -@end verbatim diff -r c9133c87760d -r 7ff69b244b5b doc/tutorial/conceptual-overview.texi --- a/doc/tutorial/conceptual-overview.texi Sun Jan 02 22:57:04 2011 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,847 +0,0 @@ - -@c ======================================================================== -@c Begin document body here -@c ======================================================================== - -@c ======================================================================== -@c Conceptual Overview -@c ======================================================================== -@node Conceptual Overview -@chapter Conceptual Overview - -@menu -* Key Abstractions:: -* A First ns-3 Script:: -@end menu - -The first thing we need to do before actually starting to look at or write -@command{ns-3} code is to explain a few core concepts and abstractions in the -system. Much of this may appear transparently obvious to some, but we -recommend taking the time to read through this section just to ensure you -are starting on a firm foundation. - -@node Key Abstractions -@section Key Abstractions - -In this section, we'll review some terms that are commonly used in -networking, but have a specific meaning in @command{ns-3}. - -@subsection Node -@cindex Node -In Internet jargon, a computing device that connects to a network is called -a @emph{host} or sometimes an @emph{end system}. Because @command{ns-3} is a -@emph{network} simulator, not specifically an @emph{Internet} simulator, we -intentionally do not use the term host since it is closely associated with -the Internet and its protocols. Instead, we use a more generic term also -used by other simulators that originates in Graph Theory --- the @emph{node}. - -@cindex class Node -In @command{ns-3} the basic computing device abstraction is called the -node. This abstraction is represented in C++ by the class @code{Node}. The -@code{Node} class provides methods for managing the representations of -computing devices in simulations. - -You should think of a @code{Node} as a computer to which you will add -functionality. One adds things like applications, protocol stacks and -peripheral cards with their associated drivers to enable the computer to do -useful work. We use the same basic model in @command{ns-3}. - -@subsection Application -@cindex Application -Typically, computer software is divided into two broad classes. @emph{System -Software} organizes various computer resources such as memory, processor -cycles, disk, network, etc., according to some computing model. System -software usually does not use those resources to complete tasks that directly -benefit a user. A user would typically run an @emph{application} that acquires -and uses the resources controlled by the system software to accomplish some -goal. - -@cindex system call -Often, the line of separation between system and application software is made -at the privilege level change that happens in operating system traps. -In @command{ns-3} there is no real concept of operating system and especially -no concept of privilege levels or system calls. We do, however, have the -idea of an application. Just as software applications run on computers to -perform tasks in the ``real world,'' @command{ns-3} applications run on -@command{ns-3} @code{Nodes} to drive simulations in the simulated world. - -@cindex class Application -In @command{ns-3} the basic abstraction for a user program that generates some -activity to be simulated is the application. This abstraction is represented -in C++ by the class @code{Application}. The @code{Application} class provides -methods for managing the representations of our version of user-level -applications in simulations. Developers are expected to specialize the -@code{Application} class in the object-oriented programming sense to create new -applications. In this tutorial, we will use specializations of class -@code{Application} called @code{UdpEchoClientApplication} and -@code{UdpEchoServerApplication}. As you might expect, these applications -compose a client/server application set used to generate and echo simulated -network packets - -@subsection Channel -@cindex Channel - -In the real world, one can connect a computer to a network. Often the media -over which data flows in these networks are called @emph{channels}. When -you connect your Ethernet cable to the plug in the wall, you are connecting -your computer to an Ethernet communication channel. In the simulated world -of @command{ns-3}, one connects a @code{Node} to an object representing a -communication channel. Here the basic communication subnetwork abstraction -is called the channel and is represented in C++ by the class @code{Channel}. - -The @code{Channel} class provides methods for managing communication -subnetwork objects and connecting nodes to them. @code{Channels} may also be -specialized by developers in the object oriented programming sense. A -@code{Channel} specialization may model something as simple as a wire. The -specialized @code{Channel} can also model things as complicated as a large -Ethernet switch, or three-dimensional space full of obstructions in the case -of wireless networks. - -We will use specialized versions of the @code{Channel} called -@code{CsmaChannel}, @code{PointToPointChannel} and @code{WifiChannel} in this -tutorial. The @code{CsmaChannel}, for example, models a version of a -communication subnetwork that implements a @emph{carrier sense multiple -access} communication medium. This gives us Ethernet-like functionality. - -@subsection Net Device -@cindex NetDevice -@cindex Ethernet -It used to be the case that if you wanted to connect a computers to a network, -you had to buy a specific kind of network cable and a hardware device called -(in PC terminology) a @emph{peripheral card} that needed to be installed in -your computer. If the peripheral card implemented some networking function, -they were called Network Interface Cards, or @emph{NICs}. Today most -computers come with the network interface hardware built in and users don't -see these building blocks. - -A NIC will not work without a software driver to control the hardware. In -Unix (or Linux), a piece of peripheral hardware is classified as a -@emph{device}. Devices are controlled using @emph{device drivers}, and network -devices (NICs) are controlled using @emph{network device drivers} -collectively known as @emph{net devices}. In Unix and Linux you refer -to these net devices by names such as @emph{eth0}. - -In @command{ns-3} the @emph{net device} abstraction covers both the software -driver and the simulated hardware. A net device is ``installed'' in a -@code{Node} in order to enable the @code{Node} to communicate with other -@code{Nodes} in the simulation via @code{Channels}. Just as in a real -computer, a @code{Node} may be connected to more than one @code{Channel} via -multiple @code{NetDevices}. - -The net device abstraction is represented in C++ by the class @code{NetDevice}. -The @code{NetDevice} class provides methods for managing connections to -@code{Node} and @code{Channel} objects; and may be specialized by developers -in the object-oriented programming sense. We will use the several specialized -versions of the @code{NetDevice} called @code{CsmaNetDevice}, -@code{PointToPointNetDevice}, and @code{WifiNetDevice} in this tutorial. -Just as an Ethernet NIC is designed to work with an Ethernet network, the -@code{CsmaNetDevice} is designed to work with a @code{CsmaChannel}; the -@code{PointToPointNetDevice} is designed to work with a -@code{PointToPointChannel} and a @code{WifiNetNevice} is designed to work with -a @code{WifiChannel}. - -@subsection Topology Helpers -@cindex helper -@cindex topology -@cindex topology helper -In a real network, you will find host computers with added (or built-in) -NICs. In @command{ns-3} we would say that you will find @code{Nodes} with -attached @code{NetDevices}. In a large simulated network you will need to -arrange many connections between @code{Nodes}, @code{NetDevices} and -@code{Channels}. - -Since connecting @code{NetDevices} to @code{Nodes}, @code{NetDevices} -to @code{Channels}, assigning IP addresses, etc., are such common tasks -in @command{ns-3}, we provide what we call @emph{topology helpers} to make -this as easy as possible. For example, it may take many distinct -@command{ns-3} core operations to create a NetDevice, add a MAC address, -install that net device on a @code{Node}, configure the node's protocol stack, -and then connect the @code{NetDevice} to a @code{Channel}. Even more -operations would be required to connect multiple devices onto multipoint -channels and then to connect individual networks together into internetworks. -We provide topology helper objects that combine those many distinct operations -into an easy to use model for your convenience. - -@c ======================================================================== -@c A First ns-3 script -@c ======================================================================== -@node A First ns-3 Script -@section A First ns-3 Script -@cindex first script -If you downloaded the system as was suggested above, you will have a release -of @command{ns-3} in a directory called @code{repos} under your home -directory. Change into that release directory, and you should find a -directory structure something like the following: - -@verbatim - AUTHORS doc/ README src/ waf.bat* - bindings/ examples/ RELEASE_NOTES utils/ wscript - build/ LICENSE samples/ VERSION wutils.py - CHANGES.html ns3/ scratch/ waf* wutils.pyc -@end verbatim - -@cindex first.cc -Change into the @code{examples/tutorial} directory. You should see a file named -@code{first.cc} located there. This is a script that will create a simple -point-to-point link between two nodes and echo a single packet between the -nodes. Let's take a look at that script line by line, so go ahead and open -@code{first.cc} in your favorite editor. - -@subsection Boilerplate -The first line in the file is an emacs mode line. This tells emacs about the -formatting conventions (coding style) we use in our source code. - -@verbatim - /* -*- Mode:C++; c-file-style:''gnu''; indent-tabs-mode:nil; -*- */ -@end verbatim - -This is always a somewhat controversial subject, so we might as well get it -out of the way immediately. The @code{ns-3} project, like most large -projects, has adopted a coding style to which all contributed code must -adhere. If you want to contribute your code to the project, you will -eventually have to conform to the @command{ns-3} coding standard as described -in the file @code{doc/codingstd.txt} or shown on the project web page -@uref{http://www.nsnam.org/codingstyle.html,,here}. - -We recommend that you, well, just get used to the look and feel of @code{ns-3} -code and adopt this standard whenever you are working with our code. All of -the development team and contributors have done so with various amounts of -grumbling. The emacs mode line above makes it easier to get the formatting -correct if you use the emacs editor. - -The @command{ns-3} simulator is licensed using the GNU General Public -License. You will see the appropriate GNU legalese at the head of every file -in the @command{ns-3} distribution. Often you will see a copyright notice for -one of the institutions involved in the @code{ns-3} project above the GPL -text and an author listed below. - -@verbatim - /* - * 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 - */ -@end verbatim - -@subsection Module Includes -The code proper starts with a number of include statements. - -@verbatim - #include "ns3/core-module.h" - #include "ns3/simulator-module.h" - #include "ns3/node-module.h" - #include "ns3/helper-module.h" -@end verbatim - -To help our high-level script users deal with the large number of include -files present in the system, we group includes according to relatively large -modules. We provide a single include file that will recursively load all of -the include files used in each module. Rather than having to look up exactly -what header you need, and possibly have to get a number of dependencies right, -we give you the ability to load a group of files at a large granularity. This -is not the most efficient approach but it certainly makes writing scripts much -easier. - -Each of the @command{ns-3} include files is placed in a directory called -@code{ns3} (under the build directory) during the build process to help avoid -include file name collisions. The @code{ns3/core-module.h} file corresponds -to the ns-3 module you will find in the directory @code{src/core} in your -downloaded release distribution. If you list this directory you will find a -large number of header files. When you do a build, Waf will place public -header files in an @code{ns3} directory under the appropriate -@code{build/debug} or @code{build/optimized} directory depending on your -configuration. Waf will also automatically generate a module include file to -load all of the public header files. - -Since you are, of course, following this tutorial religiously, you will -already have done a - -@verbatim - ./waf -d debug configure -@end verbatim - -in order to configure the project to perform debug builds. You will also have -done a - -@verbatim - ./waf -@end verbatim - -to build the project. So now if you look in the directory -@code{../../build/debug/ns3} you will find the four module include files shown -above. You can take a look at the contents of these files and find that they -do include all of the public include files in their respective modules. - -@subsection Ns3 Namespace -The next line in the @code{first.cc} script is a namespace declaration. - -@verbatim - using namespace ns3; -@end verbatim - -The @command{ns-3} project is implemented in a C++ namespace called -@code{ns3}. This groups all @command{ns-3}-related declarations in a scope -outside the global namespace, which we hope will help with integration with -other code. The C++ @code{using} statement introduces the @code{ns-3} -namespace into the current (global) declarative region. This is a fancy way -of saying that after this declaration, you will not have to type @code{ns3::} -scope resolution operator before all of the @code{ns-3} code in order to use -it. If you are unfamiliar with namespaces, please consult almost any C++ -tutorial and compare the @code{ns3} namespace and usage here with instances of -the @code{std} namespace and the @code{using namespace std;} statements you -will often find in discussions of @code{cout} and streams. - -@subsection Logging -The next line of the script is the following, - -@verbatim - NS_LOG_COMPONENT_DEFINE ("FirstScriptExample"); -@end verbatim - -We will use this statement as a convenient place to talk about our Doxygen -documentation system. If you look at the project web site, -@uref{http://www.nsnam.org,,ns-3 project}, you will find a link to ``Doxygen -(ns-3-dev)'' in the navigation bar. If you select this link, you will be -taken to our documentation page for the current development release. There -is also a link to ``Doxygen (stable)'' that will take you to the documentation -for the latest stable release of @code{ns-3}. - -Along the left side, you will find a graphical representation of the structure -of the documentation. A good place to start is the @code{NS-3 Modules} -``book'' in the @code{ns-3} navigation tree. If you expand @code{Modules} -you will see a list of @command{ns-3} module documentation. The concept of -module here ties directly into the module include files discussed above. It -turns out that the @command{ns-3} logging subsystem is part of the @code{core} -module, so go ahead and expand that documentation node. Now, expand the -@code{Debugging} book and then select the @code{Logging} page. - -You should now be looking at the Doxygen documentation for the Logging module. -In the list of @code{#define}s at the top of the page you will see the entry -for @code{NS_LOG_COMPONENT_DEFINE}. Before jumping in, it would probably be -good to look for the ``Detailed Description'' of the logging module to get a -feel for the overall operation. You can either scroll down or select the -``More...'' link under the collaboration diagram to do this. - -Once you have a general idea of what is going on, go ahead and take a look at -the specific @code{NS_LOG_COMPONENT_DEFINE} documentation. I won't duplicate -the documentation here, but to summarize, this line declares a logging -component called @code{FirstScriptExample} that allows you to enable and -disable console message logging by reference to the name. - -@subsection Main Function -The next lines of the script you will find are, - -@verbatim - int - main (int argc, char *argv[]) - { -@end verbatim - -This is just the declaration of the main function of your program (script). -Just as in any C++ program, you need to define a main function that will be -the first function run. There is nothing at all special here. Your -@command{ns-3} script is just a C++ program. - -The next two lines of the script are used to enable two logging components that -are built into the Echo Client and Echo Server applications: - -@verbatim - LogComponentEnable("UdpEchoClientApplication", LOG_LEVEL_INFO); - LogComponentEnable("UdpEchoServerApplication", LOG_LEVEL_INFO); -@end verbatim - -If you have read over the Logging component documentation you will have seen -that there are a number of levels of logging verbosity/detail that you can -enable on each component. These two lines of code enable debug logging at the -INFO level for echo clients and servers. This will result in the application -printing out messages as packets are sent and received during the simulation. - -Now we will get directly to the business of creating a topology and running -a simulation. We use the topology helper objects to make this job as -easy as possible. - -@subsection Topology Helpers -@subsubsection NodeContainer -The next two lines of code in our script will actually create the -@command{ns-3} @code{Node} objects that will represent the computers in the -simulation. - -@verbatim - NodeContainer nodes; - nodes.Create (2); -@end verbatim - -Let's find the documentation for the @code{NodeContainer} class before we -continue. Another way to get into the documentation for a given class is via -the @code{Classes} tab in the Doxygen pages. If you still have the Doxygen -handy, just scroll up to the top of the page and select the @code{Classes} -tab. You should see a new set of tabs appear, one of which is -@code{Class List}. Under that tab you will see a list of all of the -@command{ns-3} classes. Scroll down, looking for @code{ns3::NodeContainer}. -When you find the class, go ahead and select it to go to the documentation for -the class. - -You may recall that one of our key abstractions is the @code{Node}. This -represents a computer to which we are going to add things like protocol stacks, -applications and peripheral cards. The @code{NodeContainer} topology helper -provides a convenient way to create, manage and access any @code{Node} objects -that we create in order to run a simulation. The first line above just -declares a NodeContainer which we call @code{nodes}. The second line calls the -@code{Create} method on the @code{nodes} object and asks the container to -create two nodes. As described in the Doxygen, the container calls down into -the @command{ns-3} system proper to create two @code{Node} objects and stores -pointers to those objects internally. - -The nodes as they stand in the script do nothing. The next step in -constructing a topology is to connect our nodes together into a network. -The simplest form of network we support is a single point-to-point link -between two nodes. We'll construct one of those links here. - -@subsubsection PointToPointHelper -We are constructing a point to point link, and, in a pattern which will become -quite familiar to you, we use a topology helper object to do the low-level -work required to put the link together. Recall that two of our key -abstractions are the @code{NetDevice} and the @code{Channel}. In the real -world, these terms correspond roughly to peripheral cards and network cables. -Typically these two things are intimately tied together and one cannot expect -to interchange, for example, Ethernet devices and wireless channels. Our -Topology Helpers follow this intimate coupling and therefore you will use a -single @code{PointToPointHelper} to configure and connect @command{ns-3} -@code{PointToPointNetDevice} and @code{PointToPointChannel} objects in this -script. - -The next three lines in the script are, - -@verbatim - PointToPointHelper pointToPoint; - pointToPoint.SetDeviceAttribute ("DataRate", StringValue ("5Mbps")); - pointToPoint.SetChannelAttribute ("Delay", StringValue ("2ms")); -@end verbatim - -The first line, - -@verbatim - PointToPointHelper pointToPoint; -@end verbatim - -instantiates a @code{PointToPointHelper} object on the stack. From a -high-level perspective the next line, - -@verbatim - pointToPoint.SetDeviceAttribute ("DataRate", StringValue ("5Mbps")); -@end verbatim - -tells the @code{PointToPointHelper} object to use the value ``5Mbps'' -(five megabits per second) as the ``DataRate'' when it creates a -@code{PointToPointNetDevice} object. - -From a more detailed perspective, the string ``DataRate'' corresponds -to what we call an @code{Attribute} of the @code{PointToPointNetDevice}. -If you look at the Doxygen for class @code{ns3::PointToPointNetDevice} and -find the documentation for the @code{GetTypeId} method, you will find a list -of @code{Attributes} defined for the device. Among these is the ``DataRate'' -@code{Attribute}. Most user-visible @command{ns-3} objects have similar lists of -@code{Attributes}. We use this mechanism to easily configure simulations without -recompiling as you will see in a following section. - -Similar to the ``DataRate'' on the @code{PointToPointNetDevice} you will find a -``Delay'' @code{Attribute} associated with the @code{PointToPointChannel}. The -final line, - -@verbatim - pointToPoint.SetChannelAttribute ("Delay", StringValue ("2ms")); -@end verbatim - -tells the @code{PointToPointHelper} to use the value ``2ms'' (two milliseconds) -as the value of the transmission delay of every point to point channel it -subsequently creates. - -@subsubsection NetDeviceContainer -At this point in the script, we have a @code{NodeContainer} that contains -two nodes. We have a @code{PointToPointHelper} that is primed and ready to -make @code{PointToPointNetDevices} and wire @code{PointToPointChannel} objects -between them. Just as we used the @code{NodeContainer} topology helper object -to create the @code{Nodes} for our simulation, we will ask the -@code{PointToPointHelper} to do the work involved in creating, configuring and -installing our devices for us. We will need to have a list of all of the -NetDevice objects that are created, so we use a NetDeviceContainer to hold -them just as we used a NodeContainer to hold the nodes we created. The -following two lines of code, - -@verbatim - NetDeviceContainer devices; - devices = pointToPoint.Install (nodes); -@end verbatim - -will finish configuring the devices and channel. The first line declares the -device container mentioned above and the second does the heavy lifting. The -@code{Install} method of the @code{PointToPointHelper} takes a -@code{NodeContainer} as a parameter. Internally, a @code{NetDeviceContainer} -is created. For each node in the @code{NodeContainer} (there must be exactly -two for a point-to-point link) a @code{PointToPointNetDevice} is created and -saved in the device container. A @code{PointToPointChannel} is created and -the two @code{PointToPointNetDevices} are attached. When objects are created -by the @code{PointToPointHelper}, the @code{Attributes} previously set in the -helper are used to initialize the corresponding @code{Attributes} in the -created objects. - -After executing the @code{pointToPoint.Install (nodes)} call we will have -two nodes, each with an installed point-to-point net device and a single -point-to-point channel between them. Both devices will be configured to -transmit data at five megabits per second over the channel which has a two -millisecond transmission delay. - -@subsubsection InternetStackHelper -We now have nodes and devices configured, but we don't have any protocol stacks -installed on our nodes. The next two lines of code will take care of that. - -@verbatim - InternetStackHelper stack; - stack.Install (nodes); -@end verbatim - -The @code{InternetStackHelper} is a topology helper that is to internet stacks -what the @code{PointToPointHelper} is to point-to-point net devices. The -@code{Install} method takes a @code{NodeContainer} as a parameter. When it is -executed, it will install an Internet Stack (TCP, UDP, IP, etc.) on each of -the nodes in the node container. - -@subsubsection Ipv4AddressHelper -Next we need to associate the devices on our nodes with IP addresses. We -provide a topology helper to manage the allocation of IP addresses. The only -user-visible API is to set the base IP address and network mask to use when -performing the actual address allocation (which is done at a lower level -inside the helper). - -The next two lines of code in our example script, @code{first.cc}, - -@verbatim - Ipv4AddressHelper address; - address.SetBase ("10.1.1.0", "255.255.255.0"); -@end verbatim - -declare an address helper object and tell it that it should begin allocating IP -addresses from the network 10.1.1.0 using the mask 255.255.255.0 to define -the allocatable bits. By default the addresses allocated will start at one -and increase monotonically, so the first address allocated from this base will -be 10.1.1.1, followed by 10.1.1.2, etc. The low level @command{ns-3} system -actually remembers all of the IP addresses allocated and will generate a -fatal error if you accidentally cause the same address to be generated twice -(which is a very hard to debug error, by the way). - -The next line of code, - -@verbatim - Ipv4InterfaceContainer interfaces = address.Assign (devices); -@end verbatim - -performs the actual address assignment. In @command{ns-3} we make the -association between an IP address and a device using an @code{Ipv4Interface} -object. Just as we sometimes need a list of net devices created by a helper -for future reference we sometimes need a list of @code{Ipv4Interface} objects. -The @code{Ipv4InterfaceContainer} provides this functionality. - -Now we have a point-to-point network built, with stacks installed and IP -addresses assigned. What we need at this point are applications to generate -traffic. - -@subsection Applications -Another one of the core abstractions of the ns-3 system is the -@code{Application}. In this script we use two specializations of the core -@command{ns-3} class @code{Application} called @code{UdpEchoServerApplication} -and @code{UdpEchoClientApplication}. Just as we have in our previous -explanations, we use helper objects to help configure and manage the -underlying objects. Here, we use @code{UdpEchoServerHelper} and -@code{UdpEchoClientHelper} objects to make our lives easier. - -@subsubsection UdpEchoServerHelper -The following lines of code in our example script, @code{first.cc}, are used -to set up a UDP echo server application on one of the nodes we have previously -created. - -@verbatim - UdpEchoServerHelper echoServer (9); - - ApplicationContainer serverApps = echoServer.Install (nodes.Get (1)); - serverApps.Start (Seconds (1.0)); - serverApps.Stop (Seconds (10.0)); -@end verbatim - -The first line of code in the above snippet declares the -@code{UdpEchoServerHelper}. As usual, this isn't the application itself, it -is an object used to help us create the actual applications. One of our -conventions is to place @emph{required} @code{Attributes} in the helper constructor. -In this case, the helper can't do anything useful unless it is provided with -a port number that the client also knows about. Rather than just picking one -and hoping it all works out, we require the port number as a parameter to the -constructor. The constructor, in turn, simply does a @code{SetAttribute} -with the passed value. If you want, you can set the ``Port'' @code{Attribute} -to another value later using @code{SetAttribute}. - -Similar to many other helper objects, the @code{UdpEchoServerHelper} object -has an @code{Install} method. It is the execution of this method that actually -causes the underlying echo server application to be instantiated and attached -to a node. Interestingly, the @code{Install} method takes a -@code{NodeContainter} as a parameter just as the other @code{Install} methods -we have seen. This is actually what is passed to the method even though it -doesn't look so in this case. There is a C++ @emph{implicit conversion} at -work here that takes the result of @code{nodes.Get (1)} (which returns a smart -pointer to a node object --- @code{Ptr}) and uses that in a constructor -for an unnamed @code{NodeContainer} that is then passed to @code{Install}. -If you are ever at a loss to find a particular method signature in C++ code -that compiles and runs just fine, look for these kinds of implicit conversions. - -We now see that @code{echoServer.Install} is going to install a -@code{UdpEchoServerApplication} on the node found at index number one of the -@code{NodeContainer} we used to manage our nodes. @code{Install} will return -a container that holds pointers to all of the applications (one in this case -since we passed a @code{NodeContainer} containing one node) created by the -helper. - -Applications require a time to ``start'' generating traffic and may take an -optional time to ``stop''. We provide both. These times are set using the -@code{ApplicationContainer} methods @code{Start} and @code{Stop}. These -methods take @code{Time} parameters. In this case, we use an @emph{explicit} -C++ conversion sequence to take the C++ double 1.0 and convert it to an -@command{ns-3} @code{Time} object using a @code{Seconds} cast. Be aware that -the conversion rules may be controlled by the model author, and C++ has its -own rules, so you can't always just assume that parameters will be happily -converted for you. The two lines, - -@verbatim - serverApps.Start (Seconds (1.0)); - serverApps.Stop (Seconds (10.0)); -@end verbatim - -will cause the echo server application to @code{Start} (enable itself) at one -second into the simulation and to @code{Stop} (disable itself) at ten seconds -into the simulation. By virtue of the fact that we have declared a simulation -event (the application stop event) to be executed at ten seconds, the simulation -will last @emph{at least} ten seconds. - -@subsubsection UdpEchoClientHelper - -The echo client application is set up in a method substantially similar to -that for the server. There is an underlying @code{UdpEchoClientApplication} -that is managed by an @code{UdpEchoClientHelper}. - -@verbatim - UdpEchoClientHelper echoClient (interfaces.GetAddress (1), 9); - echoClient.SetAttribute ("MaxPackets", UintegerValue (1)); - echoClient.SetAttribute ("Interval", TimeValue (Seconds (1.))); - echoClient.SetAttribute ("PacketSize", UintegerValue (1024)); - - ApplicationContainer clientApps = echoClient.Install (nodes.Get (0)); - clientApps.Start (Seconds (2.0)); - clientApps.Stop (Seconds (10.0)); -@end verbatim - -For the echo client, however, we need to set five different @code{Attributes}. -The first two @code{Attributes} are set during construction of the -@code{UdpEchoClientHelper}. We pass parameters that are used (internally to -the helper) to set the ``RemoteAddress'' and ``RemotePort'' @code{Attributes} -in accordance with our convention to make required @code{Attributes} parameters -in the helper constructors. - -Recall that we used an @code{Ipv4InterfaceContainer} to keep track of the IP -addresses we assigned to our devices. The zeroth interface in the -@code{interfaces} container is going to correspond to the IP address of the -zeroth node in the @code{nodes} container. The first interface in the -@code{interfaces} container corresponds to the IP address of the first node -in the @code{nodes} container. So, in the first line of code (from above), we -are creating the helper and telling it so set the remote address of the client -to be the IP address assigned to the node on which the server resides. We -also tell it to arrange to send packets to port nine. - -The ``MaxPackets'' @code{Attribute} tells the client the maximum number of -packets we allow it to send during the simulation. The ``Interval'' -@code{Attribute} tells the client how long to wait between packets, and the -``PacketSize'' @code{Attribute} tells the client how large its packet payloads -should be. With this particular combination of @code{Attributes}, we are -telling the client to send one 1024-byte packet. - -Just as in the case of the echo server, we tell the echo client to @code{Start} -and @code{Stop}, but here we start the client one second after the server is -enabled (at two seconds into the simulation). - -@subsection Simulator -What we need to do at this point is to actually run the simulation. This is -done using the global function @code{Simulator::Run}. - -@verbatim - Simulator::Run (); -@end verbatim - -When we previously called the methods, - -@verbatim - serverApps.Start (Seconds (1.0)); - serverApps.Stop (Seconds (10.0)); - ... - clientApps.Start (Seconds (2.0)); - clientApps.Stop (Seconds (10.0)); -@end verbatim - -we actually scheduled events in the simulator at 1.0 seconds, 2.0 seconds and -two events at 10.0 seconds. When @code{Simulator::Run} is called, the system -will begin looking through the list of scheduled events and executing them. -First it will run the event at 1.0 seconds, which will enable the echo server -application (this event may, in turn, schedule many other events). Then it -will run the event scheduled for t=2.0 seconds which will start the echo client -application. Again, this event may schedule many more events. The start event -implementation in the echo client application will begin the data transfer phase -of the simulation by sending a packet to the server. - -The act of sending the packet to the server will trigger a chain of events -that will be automatically scheduled behind the scenes and which will perform -the mechanics of the packet echo according to the various timing parameters -that we have set in the script. - -Eventually, since we only send one packet (recall the @code{MaxPackets} -@code{Attribute} was set to one), the chain of events triggered by -that single client echo request will taper off and the simulation will go -idle. Once this happens, the remaining events will be the @code{Stop} events -for the server and the client. When these events are executed, there are -no further events to process and @code{Simulator::Run} returns. The simulation -is then complete. - -All that remains is to clean up. This is done by calling the global function -@code{Simulator::Destroy}. As the helper functions (or low level -@command{ns-3} code) executed, they arranged it so that hooks were inserted in -the simulator to destroy all of the objects that were created. You did not -have to keep track of any of these objects yourself --- all you had to do -was to call @code{Simulator::Destroy} and exit. The @command{ns-3} system -took care of the hard part for you. The remaining lines of our first -@command{ns-3} script, @code{first.cc}, do just that: - -@verbatim - Simulator::Destroy (); - return 0; - } -@end verbatim - -@subsection Building Your Script -We have made it trivial to build your simple scripts. All you have to do is -to drop your script into the scratch directory and it will automatically be -built if you run Waf. Let's try it. Copy @code{examples/tutorial/first.cc} into -the @code{scratch} directory after changing back into the top level directory. - -@verbatim - cd .. - cp examples/tutorial/first.cc scratch/myfirst.cc -@end verbatim - -Now build your first example script using waf: - -@verbatim - ./waf -@end verbatim - -You should see messages reporting that your @code{myfirst} example was built -successfully. - -@verbatim - Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' - [614/708] cxx: scratch/myfirst.cc -> build/debug/scratch/myfirst_3.o - [706/708] cxx_link: build/debug/scratch/myfirst_3.o -> build/debug/scratch/myfirst - Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' - 'build' finished successfully (2.357s) -@end verbatim - -You can now run the example (note that if you build your program in the scratch -directory you must run it out of the scratch directory): - -@verbatim - ./waf --run scratch/myfirst -@end verbatim - -You should see some output: - -@verbatim - Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' - Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' - 'build' finished successfully (0.418s) - Sent 1024 bytes to 10.1.1.2 - Received 1024 bytes from 10.1.1.1 - Received 1024 bytes from 10.1.1.2 -@end verbatim - -Here you see that the build system checks to make sure that the file has been -build and then runs it. You see the logging component on the echo client -indicate that it has sent one 1024 byte packet to the Echo Server on -10.1.1.2. You also see the logging component on the echo server say that -it has received the 1024 bytes from 10.1.1.1. The echo server silently -echoes the packet and you see the echo client log that it has received its -packet back from the server. - -@c ======================================================================== -@c Browsing ns-3 -@c ======================================================================== - -@node Ns-3 Source Code -@section Ns-3 Source Code - -Now that you have used some of the @command{ns-3} helpers you may want to -have a look at some of the source code that implements that functionality. -The most recent code can be browsed on our web server at the following link: -@uref{http://code.nsnam.org/ns-3-dev}. There, you will see the Mercurial -summary page for our @command{ns-3} development tree. - -At the top of the page, you will see a number of links, - -@verbatim - summary | shortlog | changelog | graph | tags | files -@end verbatim - -Go ahead and select the @code{files} link. This is what the top-level of -most of our @emph{repositories} will look: - -@verbatim -drwxr-xr-x [up] -drwxr-xr-x bindings python files -drwxr-xr-x doc files -drwxr-xr-x examples files -drwxr-xr-x ns3 files -drwxr-xr-x samples files -drwxr-xr-x scratch files -drwxr-xr-x src files -drwxr-xr-x utils files --rw-r--r-- 2009-07-01 12:47 +0200 560 .hgignore file | revisions | annotate --rw-r--r-- 2009-07-01 12:47 +0200 1886 .hgtags file | revisions | annotate --rw-r--r-- 2009-07-01 12:47 +0200 1276 AUTHORS file | revisions | annotate --rw-r--r-- 2009-07-01 12:47 +0200 30961 CHANGES.html file | revisions | annotate --rw-r--r-- 2009-07-01 12:47 +0200 17987 LICENSE file | revisions | annotate --rw-r--r-- 2009-07-01 12:47 +0200 3742 README file | revisions | annotate --rw-r--r-- 2009-07-01 12:47 +0200 16171 RELEASE_NOTES file | revisions | annotate --rw-r--r-- 2009-07-01 12:47 +0200 6 VERSION file | revisions | annotate --rwxr-xr-x 2009-07-01 12:47 +0200 88110 waf file | revisions | annotate --rwxr-xr-x 2009-07-01 12:47 +0200 28 waf.bat file | revisions | annotate --rw-r--r-- 2009-07-01 12:47 +0200 35395 wscript file | revisions | annotate --rw-r--r-- 2009-07-01 12:47 +0200 7673 wutils.py file | revisions | annotate -@end verbatim - -Our example scripts are in the @code{examples} directory. If you click on @code{examples} -you will see a list of files. One of the files in that directory is @code{first.cc}. If -you click on @code{first.cc} you will find the code you just walked through. - -The source code is mainly in the @code{src} directory. You can view source -code either by clicking on the directory name or by clicking on the @code{files} -link to the right of the directory name. If you click on the @code{src} -directory, you will be taken to the listing of the @code{src} subdirectories. If you -then click on @code{core} subdirectory, you will find a list of files. The first file -you will find (as of this writing) is @code{abort.h}. If you click on the -@code{abort.h} link, you will be sent to the source file for @code{abort.h} which -contains useful macros for exiting scripts if abnormal conditions are detected. - -The source code for the helpers we have used in this chapter can be found in the -@code{src/helper} directory. Feel free to poke around in the directory tree to -get a feel for what is there and the style of @command{ns-3} programs. diff -r c9133c87760d -r 7ff69b244b5b doc/tutorial/conclusion.texi --- a/doc/tutorial/conclusion.texi Sun Jan 02 22:57:04 2011 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,60 +0,0 @@ -@c ============================================================================ -@c Begin document body here -@c ============================================================================ - -@c ============================================================================ -@c PART: Closing Remarks -@c ============================================================================ -@c The below chapters are under the major heading "Closing Remarks" -@c This is similar to the Latex \part command -@c -@c ============================================================================ -@c Closing Remarks -@c ============================================================================ -@node Closing Remarks -@chapter Closing Remarks - -@menu -* Futures:: -* Closing:: -@end menu - -@c ============================================================================ -@c Futures -@c ============================================================================ -@node -@section Futures - -This document is a work in process. We hope and expect it to grow over time -to cover more and more of the nuts and bolts of @command{ns-3}. - -We hope to add the following chapters over the next few releases: - -@itemize @bullet -@item The Callback System -@item The Object System and Memory Management -@item The Routing System -@item Adding a New NetDevice and Channel -@item Adding a New Protocol -@item Working with Real Networks and Hosts -@end itemize - -Writing manual and tutorial chapters is not something we all get excited about, -but it is very important to the project. If you are an expert in one of these -areas, please consider contributing to @command{ns-3} by providing one of these -chapters; or any other chapter you may think is important. - -@c ============================================================================ -@c Closing -@c ============================================================================ -@node -@section Closing - -@code{ns-3} is a large and complicated system. It is impossible to cover all -of the things you will need to know in one small tutorial. - -We have really just scratched the surface of @command{ns-3} in this tutorial, -but we hope to have covered enough to get you started doing useful networking -research using our favorite simulator. - --- The @command{ns-3} development team. diff -r c9133c87760d -r 7ff69b244b5b doc/tutorial/getting-started.texi --- a/doc/tutorial/getting-started.texi Sun Jan 02 22:57:04 2011 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,559 +0,0 @@ - -@c ======================================================================== -@c Begin document body here -@c ======================================================================== - -@c ======================================================================== -@c PART: Getting Started -@c ======================================================================== -@c The below chapters are under the major heading "Getting Started" -@c This is similar to the Latex \part command -@c -@c ======================================================================== -@c Getting Started -@c ======================================================================== -@node Getting Started -@chapter Getting Started - -@menu -* Downloading ns-3:: -* Building ns-3:: -* Testing ns-3:: -* Running a Script:: -@end menu - -@c ======================================================================== -@c Downloading ns-3 -@c ======================================================================== - -@node Downloading ns-3 -@section Downloading ns-3 - -@cindex Prerequisites -@cindex Dependencies -The @command{ns-3} system as a whole is a fairly complex system and has a -number of dependencies on other components. Along with the systems you will -most likely deal with every day (the GNU toolchain, Mercurial, you programmer -editor) you will need to ensure that a number of additional libraries are -present on your system before proceeding. @command{ns-3} provides a wiki -for your reading pleasure that includes pages with many useful hints and tips. -One such page is the ``Installation'' page, -@uref{http://www.nsnam.org/wiki/index.php/Installation}. - -The ``Prerequisites'' section of this wiki page explains which packages are -required to support common @command{ns-3} options, and also provides the -commands used to install them for common Linux variants. Cygwin users will -have to use the Cygwin installer (if you are a Cygwin user, you used it to -install Cygwin). - -You may want to take this opportunity to explore the @command{ns-3} wiki -a bit since there really is a wealth of information there. - -@cindex Linux -@cindex Cygwin -@cindex GNU -@cindex toolchain -@cindex Mercurial -@cindex Waf -From this point forward, we are going to assume that the reader is working in -Linux or a Linux emulation environment (Linux, Cygwin, etc.) and has the GNU -toolchain installed and verified along with the prerequisites mentioned -above. We are also going to assume that you have Mercurial and Waf installed -and running on the target system as described in the ``Getting Started'' section -of the @command{ns-3} web site: -@uref{http://www.nsnam.org/getting_started.html}. - -@cindex tarball -The @command{ns-3} code is available in Mercurial repositories on the server -@uref{http://code.nsnam.org}. You can also download a tarball release at -@uref{http://www.nsnam.org/releases/}, or you can work with repositories -using Mercurial. We recommend using Mercurial unless there's a good reason -not to. See the end of this section for instructions on how to get a tarball -release. - -@cindex repository -The simplest way to get started using Mercurial repositories is to use the -@code{ns-3-allinone} environment. This is a set of scripts that manages the -downloading and building of various subsystems of @command{ns-3} for you. We -recommend that you begin your @command{ns-3} adventures in this environment -as it can really simplify your life at this point. - -@subsection Downloading ns-3 Using Mercurial -One practice is to create a directory called @code{repos} in one's home -directory under which one can keep local Mercurial repositories. -@emph{Hint: we will assume you do this later in the tutorial.} If you adopt -that approach, you can get a copy of @code{ns-3-allinone} by typing the -following into your Linux shell (assuming you have installed Mercurial): - -@verbatim - cd - mkdir repos - cd repos - hg clone http://code.nsnam.org/ns-3-allinone -@end verbatim - -As the hg (Mercurial) command executes, you should see something like the -following displayed, - -@verbatim - destination directory: ns-3-allinone - requesting all changes - adding changesets - adding manifests - adding file changes - added 31 changesets with 45 changes to 7 files - 7 files updated, 0 files merged, 0 files removed, 0 files unresolved -@end verbatim - -After the clone command completes, you should have a directory called -@code{ns-3-allinone} under your @code{~/repos} directory, the contents of which should -look something like the following: - -@verbatim - build.py* constants.py dist.py* download.py* README util.py -@end verbatim - -Notice that you really just downloaded some Python scripts. The next step -will be to use those scripts to download and build the @command{ns-3} -distribution of your choice. - -@cindex repository -If you go to the following link: @uref{http://code.nsnam.org/}, -you will see a number of repositories. Many are the private repositories of -the @command{ns-3} development team. The repositories of interest to you will -be prefixed with ``ns-3''. Official releases of @command{ns-3} will be -numbered as @code{ns-3..}. For example, a second hotfix to a -still hypothetical release nine of @command{ns-3} would be numbered as -@code{ns-3.9.2}. - -The current development snapshot (unreleased) of @command{ns-3} may be found -at @uref{http://code.nsnam.org/ns-3-dev/}. The -developers attempt to keep these repository in consistent, working states but -they are in a development area with unreleased code present, so you may want -to consider staying with an official release if you do not need newly- -introduced features. - -Since the release numbers are going to be changing, I will stick with -the more constant ns-3-dev here in the tutorial, but you can replace the -string ``ns-3-dev'' with your choice of release (e.g., ns-3.6) in the -text below. You can find the latest version of the -code either by inspection of the repository list or by going to the -@uref{http://www.nsnam.org/getting_started.html,,``Getting Started''} -web page and looking for the latest release identifier. - -Go ahead and change into the @code{ns-3-allinone} directory you created when -you cloned that repository. We are now going to use the @code{download.py} -script to pull down the various pieces of @command{ns-3} you will be using. - -Go ahead and type the following into your shell (remember you can substitute -the name of your chosen release number instead of @code{ns-3-dev} -- like -@code{"ns-3.6"} if you want to work with a -stable release). - -@verbatim - ./download.py -n ns-3-dev -@end verbatim - -Note that the default for the @code{-n} option is @code{ns-3-dev} and so the -above is actually redundant. We provide this example to illustrate how to -specify alternate repositories. In order to download @code{ns-3-dev} you -can actually use the defaults and simply type, - -@verbatim - ./download.py -@end verbatim - -As the hg (Mercurial) command executes, you should see something like the -following, - -@verbatim - # - # Get NS-3 - # - - Cloning ns-3 branch - => hg clone http://code.nsnam.org/ns-3-dev ns-3-dev - requesting all changes - adding changesets - adding manifests - adding file changes - added 4634 changesets with 16500 changes to 1762 files - 870 files updated, 0 files merged, 0 files removed, 0 files unresolved -@end verbatim - -This is output by the download script as it fetches the actual @code{ns-3} -code from the repository. - -The download script is smart enough to know that on some platforms various -pieces of ns-3 are not supported. On your platform you may not see some -of these pieces come down. However, on most platforms, the process should -continue with something like, - -@verbatim - # - # Get PyBindGen - # - - Required pybindgen version: 0.10.0.640 - Trying to fetch pybindgen; this will fail if no network connection is available. Hit Ctrl-C to skip. - => bzr checkout -rrevno:640 https://launchpad.net/pybindgen pybindgen - Fetch was successful. -@end verbatim - -This was the download script getting the Python bindings generator for you. -Note that you will need bazaar (bzr), a version control system, to download -PyBindGen. Next you should see (modulo platform variations) something along -the lines of, - -@verbatim - # - # Get NSC - # - - Required NSC version: nsc-0.5.0 - Retrieving nsc from https://secure.wand.net.nz/mercurial/nsc - => hg clone https://secure.wand.net.nz/mercurial/nsc nsc - requesting all changes - adding changesets - adding manifests - adding file changes - added 273 changesets with 17565 changes to 15175 files - 10622 files updated, 0 files merged, 0 files removed, 0 files unresolved -@end verbatim - -This part of the process is the script downloading the Network Simulation -Cradle for you. Note that NSC is not supported on OSX or Cygwin and works -best with gcc-3.4 or gcc-4.2 or greater series. - -After the download.py script completes, you should have several new directories -under @code{~/repos/ns-3-allinone}: - -@verbatim - build.py* constants.pyc download.py* nsc/ README util.pyc - constants.py dist.py* ns-3-dev/ pybindgen/ util.py -@end verbatim - -Go ahead and change into @code{ns-3-dev} under your @code{~/repos/ns-3-allinone} -directory. You should see something like the following there: - -@verbatim - AUTHORS examples/ RELEASE_NOTES utils/ wscript - bindings/ LICENSE samples/ VERSION wutils.py - CHANGES.html ns3/ scratch/ waf* - doc/ README src/ waf.bat* -@end verbatim - -You are now ready to build the @command{ns-3} distribution. - -@subsection Downloading ns-3 Using a Tarball -The process for downloading @command{ns-3} via tarball is simpler than the -Mercurial process since all of the pieces are pre-packaged for you. You just -have to pick a release, download it and decompress it. - -As mentioned above, one practice is to create a directory called @code{repos} -in one's home directory under which one can keep local Mercurial repositories. -One could also keep a @code{tarballs} directory. @emph{Hint: the tutorial -will assume you downloaded into a @code{repos} directory, so remember the -placekeeper.} If you adopt the @code{tarballs} directory approach, you can -get a copy of a release by typing the following into your Linux shell -(substitute the appropriate version numbers, of course): - -@verbatim - cd - mkdir tarballs - cd tarballs - wget http://www.nsnam.org/releases/ns-allinone-3.6.tar.bz2 - tar xjf ns-allinone-3.6.tar.bz2 -@end verbatim - -If you change into the directory @code{ns-allinone-3.6} you should see a -number of files: - -@verbatim -build.py* ns-3.6/ pybindgen-0.12.0.700/ util.py -constants.py nsc-0.5.1/ README -@end verbatim - -You are now ready to build the @command{ns-3} distribution. - -@c ======================================================================== -@c Building ns-3 -@c ======================================================================== - -@node Building ns-3 -@section Building ns-3 - -@subsection Building with build.py -@cindex building with build.py -The first time you build the @command{ns-3} project you should build using the -@command{allinone} environment. This will get the project configured for you -in the most commonly useful way. - -Change into the directory you created in the download section above. If you -downloaded using Mercurial you should have a directory called -@code{ns-3-allinone} under your @code{~/repos} directory. If you downloaded -using a tarball you should have a directory called something like -@code{ns-allinone-3.6} under your @code{~/tarballs} directory. Take a deep -breath and type the following: - -@verbatim - ./build.py -@end verbatim - -You will see lots of typical compiler output messages displayed as the build -script builds the various pieces you downloaded. Eventually you should see the -following magic words: - -@verbatim - Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' - 'build' finished successfully (2m30.586s) -@end verbatim - -Once the project has built you can say goodbye to your old friends, the -@code{ns-3-allinone} scripts. You got what you needed from them and will now -interact directly with Waf and we do it in the @code{ns-3-dev} directory, -not in the @code{ns-3-allinone} directory. Go ahead and change into the -@code{ns-3-dev} directory (or the directory for the appropriate release you -downloaded. - -@verbatim - cd ns-3-dev -@end verbatim - -@subsection Building with Waf -@cindex building with Waf -@cindex configuring Waf -@cindex building debug version with Waf -@cindex compiling with Waf -@cindex unit tests with Waf -We use Waf to configure and build the @command{ns-3} project. It's not -strictly required at this point, but it will be valuable to take a slight -detour and look at how to make changes to the configuration of the project. -Probably the most useful configuration change you can make will be to -build the optimized version of the code. By default you have configured -your project to build the debug version. Let's tell the project to do -make an optimized build. To explain to Waf that it should do optimized -builds you will need to execute the following command, - -@verbatim - ./waf -d optimized configure -@end verbatim - -This runs Waf out of the local directory (which is provided as a convenience -for you). As the build system checks for various dependencies you should see -output that looks similar to the following, - -@verbatim - Checking for program g++ : ok /usr/bin/g++ - Checking for program cpp : ok /usr/bin/cpp - Checking for program ar : ok /usr/bin/ar - Checking for program ranlib : ok /usr/bin/ranlib - Checking for g++ : ok - Checking for program pkg-config : ok /usr/bin/pkg-config - Checking for -Wno-error=deprecated-declarations support : yes - Checking for -Wl,--soname=foo support : yes - Checking for header stdlib.h : ok - Checking for header signal.h : ok - Checking for header pthread.h : ok - Checking for high precision time implementation : 128-bit integer - Checking for header stdint.h : ok - Checking for header inttypes.h : ok - Checking for header sys/inttypes.h : not found - Checking for library rt : ok - Checking for header netpacket/packet.h : ok - Checking for pkg-config flags for GSL : ok - Checking for header linux/if_tun.h : ok - Checking for pkg-config flags for GTK_CONFIG_STORE : ok - Checking for pkg-config flags for LIBXML2 : ok - Checking for library sqlite3 : ok - Checking for NSC location : ok ../nsc (guessed) - Checking for library dl : ok - Checking for NSC supported architecture x86_64 : ok - Checking for program python : ok /usr/bin/python - Checking for Python version >= 2.3 : ok 2.5.2 - Checking for library python2.5 : ok - Checking for program python2.5-config : ok /usr/bin/python2.5-config - Checking for header Python.h : ok - Checking for -fvisibility=hidden support : yes - Checking for pybindgen location : ok ../pybindgen (guessed) - Checking for Python module pybindgen : ok - Checking for pybindgen version : ok 0.10.0.640 - Checking for Python module pygccxml : ok - Checking for pygccxml version : ok 0.9.5 - Checking for program gccxml : ok /usr/local/bin/gccxml - Checking for gccxml version : ok 0.9.0 - Checking for program sudo : ok /usr/bin/sudo - Checking for program hg : ok /usr/bin/hg - Checking for program valgrind : ok /usr/bin/valgrind - ---- Summary of optional NS-3 features: - Threading Primitives : enabled - Real Time Simulator : enabled - Emulated Net Device : enabled - GNU Scientific Library (GSL) : enabled - Tap Bridge : enabled - GtkConfigStore : enabled - XmlIo : enabled - SQlite stats data output : enabled - Network Simulation Cradle : enabled - Python Bindings : enabled - Python API Scanning Support : enabled - Use sudo to set suid bit : not enabled (option --enable-sudo not selected) - Build examples and samples : enabled - Static build : not enabled (option --enable-static not selected) - 'configure' finished successfully (2.870s) -@end verbatim - -Note the last part of the above output. Some ns-3 options are not enabled by -default or require support from the underlying system to work properly. -For instance, to enable XmlTo, the library libxml-2.0 must be found on the -system. If this library were not found, the corresponding @command{ns-3} feature -would not be enabled and a message would be displayed. Note further that there is -a feature to use the program @code{sudo} to set the suid bit of certain programs. -This is not enabled by default and so this feature is reported as ``not enabled.'' - -Now go ahead and switch back to the debug build. - -@verbatim - ./waf -d debug configure -@end verbatim - -The build system is now configured and you can build the debug versions of -the @command{ns-3} programs by simply typing, - -@verbatim - ./waf -@end verbatim - -Some waf commands are meaningful during the build phase and some commands are valid -in the configuration phase. For example, if you wanted to use the emulation -features of @command{ns-3} you might want to enable setting the suid bit using -sudo as described above. This turns out to be a configuration-time command, and so -you could reconfigure using the following command - -@verbatim - ./waf -d debug --enable-sudo configure -@end verbatim - -If you do this, waf will have run sudo to change the socket creator programs of the -emulation code to run as root. There are many other configure- and build-time options -available in waf. To explore these options, type: - -@verbatim - ./waf --help -@end verbatim - -We'll use some of the testing-related commands in the next section. - -Okay, sorry, I made you build the @command{ns-3} part of the system twice, -but now you know how to change the configuration and build optimized code. - -@c ======================================================================== -@c Testing ns-3 -@c ======================================================================== - -@node Testing ns-3 -@section Testing ns-3 - -@cindex unit tests -You can run the unit tests of the @command{ns-3} distribution by running the -``./test.py -c core'' script, - -@verbatim - ./test.py -c core -@end verbatim - -These tests are run in parallel by waf. You should eventually -see a report saying that, - -@verbatim - 47 of 47 tests passed (47 passed, 0 failed, 0 crashed, 0 valgrind errors) -@end verbatim - -This is the important message. - -You will also see output from the test runner and the output will actually look something like, - -@verbatim - Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' - Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' - 'build' finished successfully (1.799s) - PASS: TestSuite ns3-wifi-interference - PASS: TestSuite histogram - PASS: TestSuite sample - PASS: TestSuite ipv4-address-helper - PASS: TestSuite devices-wifi - PASS: TestSuite propagation-loss-model - - ... - - PASS: TestSuite attributes - PASS: TestSuite config - PASS: TestSuite global-value - PASS: TestSuite command-line - PASS: TestSuite basic-random-number - PASS: TestSuite object - PASS: TestSuite random-number-generators - 47 of 47 tests passed (47 passed, 0 failed, 0 crashed, 0 valgrind errors) -@end verbatim - -This command is typically run by @code{users} to quickly verify that an -@command{ns-3} distribution has built correctly. - -@c ======================================================================== -@c Running a Script -@c ======================================================================== - -@node Running a Script -@section Running a Script -@cindex running a script with Waf -We typically run scripts under the control of Waf. This allows the build -system to ensure that the shared library paths are set correctly and that -the libraries are available at run time. To run a program, simply use the -@code{--run} option in Waf. Let's run the @command{ns-3} equivalent of the -ubiquitous hello world program by typing the following: - -@verbatim - ./waf --run hello-simulator -@end verbatim - -Waf first checks to make sure that the program is built correctly and -executes a build if required. Waf then executes the program, which -produces the following output. - -@verbatim - Hello Simulator -@end verbatim - -@emph{Congratulations. You are now an ns-3 user.} - -@emph{What do I do if I don't see the output?} - -If you don't see @code{waf} messages indicating that the build was -completed successfully, but do not see the ``Hello Simulator'' output, -chances are that you have switched your build mode to ``optimized'' in -the ``Building with Waf'' section, but have missed the change back to -``debug'' mode. All of the console output used in this tutorial uses a -special @command{ns-3} logging component that is useful for printing -user messages to the console. Output from this component is -automatically disabled when you compile optimized code -- it is -``optimized out.'' If you don't see the ``Hello Simulator'' output, -type the following, - -@verbatim - ./waf -d debug configure -@end verbatim - -to tell @code{waf} to build the debug versions of the @command{ns-3} -programs. You must still build the actual debug version of the code by -typing, - -@verbatim - ./waf -@end verbatim - -Now, if you run the @code{hello-simulator} program, you should see the -expected output. - -If you want to run programs under another tool such as gdb or valgrind, -see this @uref{http://www.nsnam.org/wiki/index.php/User_FAQ#How_to_run_NS-3_programs_under_another_tool,,wiki entry}. - diff -r c9133c87760d -r 7ff69b244b5b doc/tutorial/in-process/Makefile --- a/doc/tutorial/in-process/Makefile Sun Jan 02 22:57:04 2011 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,49 +0,0 @@ -TEXI2HTML = texi2html -TEXI2PDF = texi2dvi --pdf -EPSTOPDF = epstopdf -TGIF = tgif -DIA = dia -CONVERT = convert -CSS = --css-include=tutorial.css -SPLIT = --split section - -DIA_SOURCES = pp.dia dumbbell.dia star.dia -TGIF_SOURCES = helpers.obj - -DIA_EPS = ${DIA_SOURCES:.dia=.eps} -DIA_PNG = ${DIA_SOURCES:.dia=.png} -DIA_PDF = ${DIA_SOURCES:.dia=.pdf} - -TGIF_EPS = ${TGIF_SOURCES:.obj=.eps} -TGIF_PNG = ${TGIF_SOURCES:.obj=.png} -TGIF_PDF = ${TGIF_SOURCES:.obj=.pdf} - -all: images html split-html pdf - -# Note: tgif requires a valid x display to convert from .obj to .png. -# If running this makefile on a remote console, the X virtual frame -# buffer may be needed (xorg-x11-server-Xvfb) to provide a "fake" -# display -images: - cd figures/; $(DIA) -t png $(DIA_SOURCES) - cd figures/; $(DIA) -t eps $(DIA_SOURCES) - cd figures/; $(foreach FILE,$(DIA_EPS),$(EPSTOPDF) $(FILE);) - cd figures/; $(TGIF) -print -png $(TGIF_SOURCES) - cd figures/; $(TGIF) -print -eps $(TGIF_SOURCES) - cd figures/; $(foreach FILE,$(TGIF_EPS),$(EPSTOPDF) $(FILE);) - -html: images - $(TEXI2HTML) ${CSS} tutorial.texi - -split-html: images - $(TEXI2HTML) ${CSS} ${SPLIT} tutorial.texi - -pdf: images - $(TEXI2PDF) tutorial.texi - -figures-clean: - cd figures/; rm -rf $(DIA_EPS); rm -rf $(DIA_PNG); rm -rf $(DIA_PDF) - cd figures/; rm -rf $(TGIF_EPS); rm -rf $(TGIF_PNG); rm -rf $(TGIF_PDF) - -clean: figures-clean - rm -rf tutorial.aux tutorial.cp tutorial.cps tutorial.fn tutorial.ky tutorial.pg tutorial.tp tutorial.vr tutorial.toc tutorial.log tutorial.pdf tutorial.html tutorial/ diff -r c9133c87760d -r 7ff69b244b5b doc/tutorial/in-process/attributes.texi --- a/doc/tutorial/in-process/attributes.texi Sun Jan 02 22:57:04 2011 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,535 +0,0 @@ -@node ns-3 Attributes -@chapter ns-3 Attributes -@anchor{chap:Attributes} - -In ns-3 simulations, there are two main aspects to configuration: -@itemize @bullet -@item the simulation topology and how objects are connected -@item the values used by the models instantiated in the topology -@end itemize - -This chapter focuses on the second item above: how the many values -in use in ns-3 are organized, documented, and modifiable by ns-3 users. -The ns-3 attribute system is also the underpinning of how traces -and statistics are gathered in the simulator. - -Before delving into details of the attribute value system, -it will help to review some basic properties of @code{class ns3::Object}. - -@node Object Overview -@section Object Overview - -ns-3 is fundamentally a C++ object-based system. By this we mean that -new C++ classes (types) can be declared, defined, and subclassed -as usual. - -Many ns-3 objects inherit from the @code{ns3::Object} base class. These -objects have some additional properties that we exploit for -organizing the system and improving the memory management -of our objects: - -@itemize @bullet -@item a "metadata" system that links the class name to a lot of -meta-information about the object, including the base class of the subclass, -the set of accessible constructors in the subclass, and the set of -"attributes" of the subclass -@item a reference counting smart pointer implementation, for memory -management. -@end itemize - -ns-3 objects that use the attribute system derive from either -@code{ns3::Object} or @code{ns3::ObjectBase}. Most ns-3 objects -we will discuss derive from @code{ns3::Object}, but a few that -are outside the smart pointer memory management framework derive -from @code{ns3::ObjectBase}. - -Let's review a couple of properties of these objects. - -@node Smart pointers -@subsection Smart pointers - -As introduced above in @ref{Smart Pointers 101}, ns-3 objects -are memory managed by a -@uref{http://en.wikipedia.org/wiki/Smart_pointer,,reference counting smart pointer implementation}, @code{class ns3::Ptr}. - -Smart pointers are used extensively in the ns-3 APIs, to avoid passing -references to heap-allocated objects that may cause memory leaks. -For most basic usage (syntax), treat a smart pointer like a regular pointer: -@verbatim - Ptr nd = ...; - nd->CallSomeFunction (); - // etc. -@end verbatim - -@node CreateObject -@subsection CreateObject - -As we discussed above in @ref{Object Creation}, -at the lowest-level API, objects of type @code{ns3::Object} are -not instantiated using @code{operator new} as usual but instead by -a templated function called @code{CreateObject()}. - -A typical way to create such an object is as follows: -@verbatim - Ptr nd = CreateObject (); -@end verbatim - -You can think of this as being functionally equivalent to: -@verbatim - WifiNetDevice* nd = new WifiNetDevice (); -@end verbatim - -Objects that derive from @code{ns3::Object} must be allocated -on the heap using CreateObject(). Those deriving from -@code{ns3::ObjectBase}, such as ns-3 helper functions and packet -headers and trailers, can be allocated on the stack. - -In some scripts, you may not see a lot of CreateObject() calls -in the code; -this is because there are some helper objects in effect that -are doing the CreateObject()s for you. - -@node TypeId -@subsection TypeId - -ns-3 classes that derive from class ns3::Object can include -a metadata class called @code{TypeId} that records meta-information -about the class, for use in the object aggregation and component -manager systems: -@itemize @bullet - @item a unique string identifying the class - @item the base class of the subclass, within the metadata system - @item the set of accessible constructors in the subclass -@end itemize - -@node Object Summary -@subsection Object Summary - -Putting all of these concepts together, let's look at a specific -example: @code{class ns3::Node}. - -The public header file node.h has a declaration that includes -a static GetTypeId function call: -@verbatim -class Node : public Object -{ -public: - static TypeId GetTypeId (void); - ... -@end verbatim - -This is defined in the node.cc file as follows: -@verbatim -TypeId -Node::GetTypeId (void) -{ - static TypeId tid = TypeId ("ns3::Node") - .SetParent () - return tid; -} -@end verbatim -Finally, when users want to create Nodes, they call: -@verbatim - Ptr n = CreateObject n; -@end verbatim - -We next discuss how attributes (values associated with member variables -or functions of the class) are plumbed into the above TypeId. - -@node Attribute Overview -@section Attribute Overview - -The goal of the attribute system is to organize the access of -internal member objects of a simulation. This goal arises because, -typically in simulation, users will cut and paste/modify existing -simulation scripts, or will use higher-level simulation constructs, -but often will be interested in studying or tracing particular -internal variables. For instance, use cases such as: -@itemize @bullet -@item "I want to trace the packets on the wireless interface only on -the first access point" -@item "I want to trace the value of the TCP congestion window (every -time it changes) on a particular TCP socket" -@item "I want a dump of all values that were used in my simulation." -@end itemize - -Similarly, users may want fine-grained access to internal -variables in the simulation, or may want to broadly change the -initial value used for a particular parameter in all subsequently -created objects. Finally, users may wish to know what variables -are settable and retrievable in a simulation configuration. This -is not just for direct simulation interaction on the command line; -consider also a (future) graphical user interface -that would like to be able to provide a feature whereby a user -might right-click on an node on the canvas and see a hierarchical, -organized list of parameters that are settable on the node and its -constituent member objects, and help text and default values for -each parameter. - -@node Functional overview -@subsection Functional overview - -We provide a way for users to access values deep in the system, without -having to plumb accessors (pointers) through the system and walk -pointer chains to get to them. Consider a class DropTailQueue that -has a member variable that is an unsigned integer @code{m_maxPackets}; -this member variable controls the depth of the queue. - -If we look at the declaration of DropTailQueue, we see the following: -@verbatim -class DropTailQueue : public Queue { -public: - static TypeId GetTypeId (void); - ... - -private: - std::queue > m_packets; - uint32_t m_maxPackets; -}; -@end verbatim - -Let's consider things that a user may want to do with the value of -m_maxPackets: - -@itemize @bullet -@item Set a default value for the system, such that whenever a new -DropTailQueue is created, this member is initialized to that default. -@item Set or get the value on an already instantiated queue. -@end itemize - -The above things typically require providing Set() and Get() functions, -and some type of global default value. - -In the ns-3 attribute system, these value definitions and accessor -functions are moved into the TypeId class; e.g.: -@verbatim -TypeId DropTailQueue::GetTypeId (void) -{ - static TypeId tid = TypeId ("ns3::DropTailQueue") - .SetParent () - .AddConstructor () - .AddAttribute ("MaxPackets", "The maximum number of packets accepted by this DropTailQueue.", - Uinteger (100), - MakeUintegerAccessor (&DropTailQueue::m_maxPackets), - MakeUintegerChecker ()) - ; - - return tid; -} -@end verbatim - -The AddAttribute() method is performing a number of things with this -value: -@itemize @bullet -@item Binding the variable m_maxPackets to a string "MaxPackets" -@item Providing a default value (100 packets) -@item Providing some help text defining the value -@item Providing a "checker" (not used in this example) that can be used to set -bounds on the allowable range of values -@end itemize - -The key point is that now the value of this variable and its default -value are accessible in the attribute namespace, which is based on -strings such as "MaxPackets" and TypeId strings. In the next -section, we will provide an example script that shows how users -may manipulate these values. - -@node Basic usage -@subsection Basic usage - -Let's look at how a user script might access these values. -This is based on the script found at @code{samples/main-attribute-value.cc}, -with some details stripped out. -@verbatim -// -// This is a basic example of how to use the attribute system to -// set and get a value in the underlying system; namely, an unsigned -// integer of the maximum number of packets in a queue -// - -int -main (int argc, char *argv[]) -{ - - // By default, the MaxPackets attribute has a value of 100 packets - // (this default can be observed in the function DropTailQueue::GetTypeId) - // - // Here, we set it to 80 packets. We could use one of two value types: - // a string-based value or a Uinteger value - Config::SetDefault ("ns3::DropTailQueue::MaxPackets", String ("80")); - // The below function call is redundant - Config::SetDefault ("ns3::DropTailQueue::MaxPackets", Uinteger(80)); - - // Allow the user to override any of the defaults and the above - // SetDefaults() at run-time, via command-line arguments - CommandLine cmd; - cmd.Parse (argc, argv); -@end verbatim - -The main thing to notice in the above are the two calls to -@code{Config::SetDefault}. This is how we set the default value -for all subsequently instantiated DropTailQueues. We illustrate -that two types of Value classes, a String and a Uinteger class, -can be used to assign the value to the attribute named by -"ns3::DropTailQueue::MaxPackets". - -Now, we will create a few objects using the low-level API; here, -our newly created queues will not have a m_maxPackets initialized to -100 packets but to 80 packets, because of what we did above with -default values. -@verbatim - Ptr n0 = CreateObject (); - - Ptr net0 = CreateObject (); - n0->AddDevice (net0); - - Ptr q = CreateObject (); - net0->AddQueue(q); -@end verbatim - -At this point, we have created a single node (Node 0) and a -single PointToPointNetDevice (NetDevice 0) and added a -DropTailQueue to it. - -Now, we can manipulate the MaxPackets value of the already -instantiated DropTailQueue. Here are various ways to do that. - -@subsubsection Pointer-based access - -We assume that a smart pointer (Ptr) to a relevant network device is -in hand; here, it is the net0 pointer. - -One way to change the value is to access a pointer to the -underlying queue and modify its attribute. - -First, we observe that we can get a pointer to the (base class) -queue via the PointToPointNetDevice attributes, where it is called -TxQueue -@verbatim - Ptr txQueue = net0->GetAttribute ("TxQueue"); -@end verbatim - -Using the GetObject function, we can perform a safe downcast -to a DropTailQueue, where MaxPackets is a member -@verbatim - Ptr dtq = txQueue->GetObject (); - NS_ASSERT (dtq); -@end verbatim - -Next, we can get the value of an attribute on this queue -We have introduced wrapper "Value" classes for the underlying -data types, similar to Java wrappers around these types, since -the attribute system stores values and not disparate types. -Here, the attribute value is assigned to a Uinteger, and -the Get() method on this value produces the (unwrapped) uint32_t. -@verbatim - Uinteger limit = dtq->GetAttribute ("MaxPackets"); - NS_LOG_INFO ("1. dtq limit: " << limit.Get () << " packets"); -@end verbatim - -Note that the above downcast is not really needed; we could have -done the same using the Ptr even though the attribute -is a member of the subclass -@verbatim - limit = txQueue->GetAttribute ("MaxPackets"); - NS_LOG_INFO ("2. txQueue limit: " << limit.Get () << " packets"); -@end verbatim - -Now, let's set it to another value (60 packets) -@verbatim - txQueue->SetAttribute("MaxPackets", Uinteger (60)); - limit = txQueue->GetAttribute ("MaxPackets"); - NS_LOG_INFO ("3. txQueue limit changed: " << limit.Get () << " packets"); -@end verbatim - -@subsubsection Namespace-based access - -An alternative way to get at the attribute is to use the configuration -namespace. Here, this attribute resides on a known path in this -namespace; this approach is useful if one doesn't have access to -the underlying pointers and would like to configure a specific -attribute with a single statement. -@verbatim - Config::Set ("/NodeList/0/DeviceList/0/TxQueue/MaxPackets", Uinteger (25)); - limit = txQueue->GetAttribute ("MaxPackets"); - NS_LOG_INFO ("4. txQueue limit changed through namespace: " << - limit.Get () << " packets"); -@end verbatim - -We could have also used wildcards to set this value for all nodes -and all net devices (which in this simple example has the same -effect as the previous Set()) -@verbatim - Config::Set ("/NodeList/*/DeviceList/*/TxQueue/MaxPackets", Uinteger (15)); - limit = txQueue->GetAttribute ("MaxPackets"); - NS_LOG_INFO ("5. txQueue limit changed through wildcarded namespace: " << - limit.Get () << " packets"); -@end verbatim - -@node Setting through constructors and helper classes -@subsection Setting through constructors helper classes - -Arbitrary combinations of attributes can be set and fetched from -the helper and low-level APIs; either from the constructors themselves: -@verbatim -Ptr p = CreateObject ("n1", v1, "n2", v2, ...); -@end verbatim -or from the higher-level helper APIs, such as: -@verbatim - mobility.SetPositionAllocator ("GridPositionAllocator", - "MinX", FpValue (-100.0), - "MinY", FpValue (-100.0), - "DeltaX", FpValue (5.0), - "DeltaY", FpValue (20.0), - "GridWidth", UintValue (20), - "LayoutType", "RowFirst"); -@end verbatim - -@node Value classes -@subsection Value classes -Readers will note the new Value classes. These can be thought of as -an intermediate class that can be used to convert from raw types to the -Values that are used by the system. Recall that this database is holding -objects of many types with a single generic type. Conversions to this -type can either be done using an intermediate class (IntValue, FpValue for -"floating point") or via strings. Direct implicit conversion of types -to Value is not really practical. So in the above, users have a choice -of using strings or values: -@verbatim -p->Set ("cwnd", "100"); // string-based setter -p->Set ("cwnd", IntValue(100)); // value-based setter -@end verbatim - -The system provides some macros that help users declare and define -new Value subclasses for new types that they want to introduce into -the attribute system. - -@node Extending attributes -@section Extending attributes - -The ns-3 system will place a number of internal values under the -attribute system, but undoubtedly users will want to extend this -to pick up ones we have missed, or to add their own classes to this. - -@subsection Adding an existing internal variable to the metadata system - -// XXX revise me - -Consider this variable in class TcpSocket: -@verbatim - uint32_t m_cWnd; // Congestion window -@end verbatim - -Suppose that someone working with Tcp wanted to get or set the -value of that variable using the metadata system. If it were not -already provided by ns-3, the user could declare the following addition -in the metadata system (to the TypeId declaration for TcpSocket): -@verbatim - .AddParameter ("Congestion window", - "Tcp congestion window (bytes)", - MakeUIntParamSpec (&TcpSocket::m_cWnd, 1)); - -@end verbatim - -Now, the user with a pointer to the TcpSocket can perform operations -such as setting and getting the value, without having to add these -functions explicitly. Furthermore, access controls can be applied, such -as allowing the parameter to be read and not written, or bounds -checking on the permissible values can be applied. - -@subsection Adding a new TypeId - -Here, we discuss the impact on a user who wants to add a new class to -ns-3; what additional things must be done to hook it into this system. - -We've already introduced what a TypeId definition looks like: -@verbatim -TypeId -RandomWalk2dMobilityModel::GetTypeId (void) -{ - static TypeId tid = TypeId ("RandomWalkMobilityModel") - .SetParent () - .SetGroupName ("Mobility") - .AddConstructor () - // followed by a number of Parameters - .AddParameter ("bounds", - "Bounds of the area to cruise.", - MakeRectangleParamSpec (&RandomWalk2dMobilityModel::m_bounds, Rectangle (0.0, 0.0, 100.0, 100.0))) - .AddParameter ("time", - "Change current direction and speed after moving for this delay.", - MakeTimeParamSpec (&RandomWalk2dMobilityModel::m_modeTime, - Seconds (1.0))) - - // etc (more parameters). -@end verbatim - -The declaration for this in the class declaration is one-line public -member method: -@verbatim - public: - static TypeId GetTypeId (void); -@end verbatim - -@section Adding new class type to the Value system - -From the perspective of the user who writes a new class in the system and -wants to hook it in to the attribute system, there is mainly the matter -of writing -the conversions to/from strings and Values. Most of this can be -copy/pasted with macro-ized code. For instance, consider class -Rectangle in the @code{src/mobility/} directory: - -One line is added to the class declaration: -@verbatim -/** - * \brief a 2d rectangle - */ -class Rectangle -{ -... - - VALUE_HELPER_HEADER_1 (Rectangle); -}; -@end verbatim - -One templatized declaration, and two operators, are added below the -class declaration: - -@verbatim -std::ostream &operator << (std::ostream &os, const Rectangle &rectangle); -std::istream &operator >> (std::istream &is, Rectangle &rectangle); - -VALUE_HELPER_HEADER_2 (Rectangle); -@end verbatim - -In the class definition, the code looks like this: - -@verbatim -VALUE_HELPER_CPP (Rectangle); - -std::ostream & -operator << (std::ostream &os, const Rectangle &rectangle) -{ - os << rectangle.xMin << "|" << rectangle.xMax << "|" << rectangle.yMin << "|" << rectangle.yMax; - return os; -} -std::istream & -operator >> (std::istream &is, Rectangle &rectangle) - { - char c1, c2, c3; - is >> rectangle.xMin >> c1 >> rectangle.xMax >> c2 >> rectangle.yMin >> c3 >> rectangle.yMax; - if (c1 != '|' || - c2 != '|' || - c3 != '|') - { - is.setstate (std::ios_base::failbit); - } - return is; -} -@end verbatim - -These stream operators simply convert from a string representation of the -Rectangle ("xMin|xMax|yMin|yMax") to the underlying Rectangle, and the -modeler must specify these operators and the string syntactical representation -of an instance of the new class. - diff -r c9133c87760d -r 7ff69b244b5b doc/tutorial/in-process/helpers.texi --- a/doc/tutorial/in-process/helpers.texi Sun Jan 02 22:57:04 2011 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,20 +0,0 @@ -@node Helper Functions -@chapter Helper Functions -@anchor{chap:Helpers} -This chapter describes an intermediate API for the simulator; what we -call the "helper API". The helper API is implemented in -@code{src/helper/} directory; it depends on (and wraps) the low-level -API which is implemented everywhere else in @code{src/}. The following -figure shows this relationship. -@center @image{figures/helpers,,,,png} - -The use of the helper API is optional. It has two main goals: -@itemize @bullet -@item Provide "syntactic sugar" to wrap a number of related low-level -API calls together, that would normally be grouped together often, into -something that is more user-friendly. -@item Handle configuration of larger topological units (e.g., a set -of nodes or a set of nodes on a particular link) . -@end itemize - -(more to follow) diff -r c9133c87760d -r 7ff69b244b5b doc/tutorial/in-process/introduction.texi --- a/doc/tutorial/in-process/introduction.texi Sun Jan 02 22:57:04 2011 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2034 +0,0 @@ - -@c ======================================================================== -@c Begin document body here -@c ======================================================================== - -@c ======================================================================== -@c Tutorial Goals -@c ======================================================================== - -@node Tutorial Goals -@unnumbered Tutorial Goals - -@c This is an unnumbered section, like a preface. Numbering -@c starts with section 1 (Introduction) - -The goal of this ns-3 tutorial is to introduce new users of ns-3 to enough -of the system to enable them to author simple simulation scripts and extract -useful information from the simulations. We begin by introducing some of the -other important resources that are available to those interested in using or -writing scripts, models and even those interested in making contributions to -the core ns-3 system. We provide an overview of some of the -important abstractions, design patterns and idioms used when writing -ns-3 scripts, and then dig right in by beginning to write simulation -scripts, run them and interpret results. - -After completing this tutorial, one should be able to: -@itemize @bullet -@item Find documentation resources in the distribution and on the web; -@item Download and compile the ns-3 system; -@item Understand the key software conventions of ns-3; -@item Modify configuration parameters of existing scripts; -@item Change the simulation output (tracing, logging, statistics); -@item Extend the simulator to use new objects -@item Write new ns-3 applications; -@item See how to port code from ns-2; -@item ... (more to follow) -@end itemize - -@c ======================================================================== -@c PART: Introduction -@c ======================================================================== -@c The below chapters are under the major heading "Introduction" -@c This is similar to the Latex \part command -@c -@c ======================================================================== -@c Overview -@c ======================================================================== -@node Overview -@chapter Overview - -@menu -* For ns-2 users:: -* Contributing:: -* Tutorial organization:: -@end menu - -The ns-3 simulator is a discrete-event network -simulator targeted primarily for research and educational use. -The @uref{http://www.nsnam.org,,ns-3 project}, started in -2006, is an open-source project. The goal of the project is to -build a new network simulator primarily for research and educational use. - -Primary documentation for the ns-3 project is available in -three forms: -@itemize @bullet -@item @uref{http://www.nsnam.org/doxygen/index.html,,ns-3 Doxygen/Manual}: Documentation of the public APIs of the simulator -@item Tutorial (this document) -@item @uref{http://www.nsnam.org/wiki/index.php,, ns-3 wiki} -@end itemize - -The purpose of this tutorial is to introduce new ns-3 users to the -system in a structured way. It is sometimes difficult for new users to -glean essential information from detailed manuals and to convert this -information into working simulations. In this tutorial, we will build -several example simulations, introducing and explaining key concepts and -features as we go. - -As the tutorial unfolds, we will introduce the full ns-3 -documentation -and provide pointers to source code for those interested in delving deeper -into the workings of the system. - -A few key points are worth noting at the onset: -@itemize @bullet -@item ns-3 is not an extension of @uref{http://www.isi.edu/nsnam/ns,,ns-2}; -it is a new -simulator. The two simulators are both written in C++ but ns-3 -is a new simulator that does not support the ns-2 APIs. -Some models from ns-2 have already been ported from ns-2 -to ns-3. The project will continue to maintain ns-2 while -ns-3 is being built, and will study transition and -integration mechanisms. -@item ns-3 is open-source, and the project strives to maintain -an open environment for researchers to contribute and share their -software. -@end itemize - -@node For ns-2 users -@section For ns-2 users - -For those familiar with ns-2, the most visible outward change -when moving to ns-3 is the choice of scripting language. -ns-2 is typically scripted in Tcl and results of simulations can -be visualized using the Network Animator @command{nam}. In -ns-3 there is currently no visualization module, and Python -bindings have been developed (Tcl bindings have been prototyped -using @uref{http://www.swig.org,,SWIG}, but are not supported by the -current development team). -In this tutorial, we will concentrate on -scripting directly in C++ and interpreting results via trace files. - -But there are similarities as well (both, for example, are based -on C++ objects, and some code from ns-2 has already been ported -to ns-3). We will try to highlight differences between ns-2 and ns-3 -as we proceed in this tutorial. - -@node Contributing -@section Contributing - -@cindex software configuration management -ns-3 is a research and educational simulator, by and for the -research community. It will rely on the ongoing contributions of -the community to develop new models, debug or maintain -existing ones, and share results. There are a few policies -that we hope will encourage people to contribute to ns-3 like they -have for ns-2: -@itemize @bullet -@item open source licensing based on GNU GPLv2 compatibility -@item @uref{http://www.nsnam.org/wiki/index.php,,wiki} -@item @uref{http://www.nsnam.org/wiki/index.php/Contributed_Code,,Contributed Code} page, similar to ns-2's popular -@uref{http://nsnam.isi.edu/nsnam/index.php/Contributed_Code,,Contributed Code} -page -@item @code{src/contrib} directory (we will host your contributed code) -@item open @uref{http://www.nsnam.org/bugzilla,,bug tracker} -@item ns-3 developers will gladly help potential contributors to get -started with the simulator (please contact @uref{http://www.nsnam.org/people.html,,one of us}) -@end itemize - -If you are an ns user, please consider to provide your feedback, -bug fixes, or code to the project. - -@node Tutorial organization -@section Tutorial organization - -The tutorial assumes that new users might follow a path such as follows: - -@itemize @bullet -@item browse the source code and documentation, to get a feel for -the simulator and what it might be like to handle; -@item try to download and build a copy; -@item try to run a few sample programs, and perhaps change some configurations; -@item look at simulation output, and try to adjust it -@item study the software architecture of the system, to consider hacking it or -extending it; -@item write new models or port existing code to ns-3, and eventually post those -models back to the community. -@end itemize - -As a result, we have tried to organize the tutorial along the above -broad sequences of events. - -@c ======================================================================== -@c Browsing ns-3 -@c ======================================================================== - -@node Browsing -@chapter Browsing ns-3 - -@menu -* Source code:: -* Doxygen:: -* Other documentation:: -@end menu - -@node Source code -@section Source code - -The most recent code can be browsed on our web server at the following link: -@uref{http://code.nsnam.org/?sort=lastchange}. If you click on the bold -repository names on the left of the page, you will see changelogs for -these repositories, and links to the @emph{manifest}. From the manifest -links, one can browse the source tree. - -The top-level directory will look something like: -@verbatim - AUTHORS RELEASE_NOTES examples/ src/ waf* - LICENSE VERSION ns3/ tutorial/ waf.bat* - README doc/ samples/ utils/ wscript -@end verbatim -The source code is mainly in the @code{src} directory. Example -scripts are in the @code{examples} directory. Both are good directories -to start browsing some code. - -For ns-2 users, who may be familiar with the @code{simple.tcl} example script -in the ns-2 documentation, an analogous script is found in -@code{examples/simple-point-to-point.cc} with a Python equivalent found -in @emph{(pending Python merge)}. - -@node Doxygen -@section Doxygen - -We document all of APIs using @uref{http://www.stack.nl/~dimitri/doxygen/,,Doxygen}. Current builds of this documentation are available at: -@uref{http://www.nsnam.org/doxygen/index.html}, which are worth an initial -look. - -@node Other documentation -@section Other documentation - -See: @uref{http://www.nsnam.org/documents.html}. - -@c ======================================================================== -@c Resources -@c ======================================================================== - -@node Resources -@chapter Resources - -@menu -* The-Web:: -* Mercurial:: -* Waf:: -* Environment-Idioms-Design-Patterns:: -* Socket-Programming:: -@end menu - -@node The-Web -@section The Web - -@cindex www.nsnam.org -There are several important resources of which any ns-3 user must be -aware. The main web site is located at @uref{http://www.nsnam.org} -and provides access to basic information about the ns-3 system. -Detailed documentation is available through the main web site at -@uref{http://www.nsnam.org/documents.html}. - -@cindex documentation -@cindex architecture -You can find documents relating to the system architecture from this page, -and also gain access to the detailed software documentation. The software -system is documented in great detail using -@uref{http://www.stack.nl/~dimitri/doxygen/,,Doxygen}. There is a Wiki that -complements the main ns-3 web site which you will find at -@uref{http://www.nsnam.org/wiki/}. - -You will find user and developer FAQs there as well as troubleshooting guides, -third-party contributed code, papers, etc. The source code may be found -and browsed at @uref{http://code.nsnam.org/}. - -@cindex repository!ns-3-dev -@cindex repository!releases -There you will find the current development tree in the repository named -@code{ns-3-dev}. Past releases and experimental repositories of the core -developers may also be found there. - -@node Mercurial -@section Mercurial - -Complex software systems need some way to manage the organization and -changes to the underlying code and documentation. There are many ways to -perform this feat, and you may have heard of some of the systems that are -currently used to do this. The Concurrent Version System (CVS) is probably -the most well known. - -@cindex software configuration management -@cindex Mercurial -The ns-3 project uses Mercurial as its source code management system. -Although you do not need to know much about Mercurial in order to complete -this tutorial, we recommend becoming familiar with Mercurial and using it -to access the source code. Mercurial has a web site at -@uref{http://www.selenic.com/mercurial/}, -from which you can get binary or source releases of this Software -Configuration Management (SCM) system. Selenic (the developer of Mercurial) -also provides a tutorial at -@uref{http://www.selenic.com/mercurial/wiki/index.cgi/Tutorial/}, -and a QuickStart guide at -@uref{http://www.selenic.com/mercurial/wiki/index.cgi/QuickStart/}. - -You can also find vital information about using Mercurial and ns-3 -on the main ns-3 web site. - -@node Waf -@section Waf - -@cindex Waf -@cindex make -@cindex build -Once you have source code downloaded to your local system, you will need -to compile that source to produce usable programs. Just as in the case of -source code management, there are many tools available to perform this -function. Probably the most famous of these tools is @code{make}. Along -with being the most famous, @code{make} is probably the most difficult to -use in a very large and highly configurable system. Because of this, many -alternatives have been developed. Recently these systems have been developed -using the Python language. - -The build system @code{Waf} is used on the ns-3 project. It is one -of the new generation of Python-based build systems. You will not need to -understand any Python to build the existing ns-3 system, and will -only have to understand a tiny and intuitively obvious subset of Python in -order to extend the system in most cases. - -For those interested in the gory details of Waf, the main web site can be -found at @uref{http://freehackers.org/\~tnagy/waf.html}. - -@node Environment-Idioms-Design-Patterns -@section Environment, Idioms, and Design Patterns - -@cindex C++ -As mentioned above, scripting in ns-3 is done in C++. A working -knowledge of C++ and object-oriented concepts is assumed in this document. -We will take some time to review some of the more advanced concepts or -possibly unfamiliar language features, idioms and design patterns as they -appear. We don't want this tutorial to devolve into a C++ tutorial, though, -so we do expect a basic command of the language. There are an almost -unimaginable number of sources of information on C++ available on the web or -in print. - -If you are new to C++, you may want to find a tutorial- or cookbook-based -book or web site and work through at least the basic features of the language -before proceeding. - -@subsection Environment - -@cindex toolchain -@cindex GNU -The ns-3 system uses the GNU ``toolchain'' for development. -A software toolchain is the set of programming tools available in the given -environment. For a quick review of what is included in the GNU toolchain see, -@uref{http://en.wikipedia.org/wiki/GNU_toolchain}. - -@cindex Linux -Typically an ns-3 author will work in Linux or a Linux-like -environment. For those running under Windows, there do exist environments -which simulate the Linux environment to various degrees. The ns-3 -project supports development in the Cygwin and the MinGW environments for -these users. See @uref{http://www.cygwin.com/} and -@uref{http://www.mingw.org/} for details on downloading and using these -systems. Cygwin provides many of the popular Linux system commands. -It can, however, sometimes be problematic due to the way it -actually does its emulation, and sometimes interactions with other Windows -software can cause problems. - -@cindex Cygwin -@cindex MinGW -If you do use Cygwin or MinGW; and use Logitech products, we will save you -quite a bit of heartburn right off the bat and encourage you to take a look -at the @uref{http://www.mingw.org/MinGWiki/index.php/FAQ,,MinGW FAQ}. - -@cindex Logitech -Search for ``Logitech'' and read the FAQ entry, ``why does make often -crash creating a sh.exe.stackdump file when I try to compile my source code.'' -Believe it or not, the @code{Logitech Process Monitor} insinuates itself into -every DLL in the system when it is running. It can cause your Cygwin or -MinGW DLLs to die in mysterious ways and often prevents debuggers from -running. Beware of Logitech. - -@subsection Idioms and Design Patterns - -@cindex idiom -In any system, there are a number of problems to be solved that happen -repeatedly. Often the solutions to these problems can be generalized and -applied in a similar way across the system. These solutions are called -Design Patterns. The ns-3 system relies on several classic design -patterns. - -@cindex design pattern -Also, in any language, there are constructs that, while they aren't part of the -language per se, are commonly found and useful. For example, at the lowest -level a C programmer should be able to immediately recognize the purpose and -intent of the following code without having to reflect on the details: - -@verbatim - for (;;) -@end verbatim - -These low-level constructs, or idioms, extend upward in complexity, eventually -becoming implementations of design patterns. As you are exposed to more -and more of the ns-3 system, you will begin to recognize and be -comfortable with the C++ implementations (idioms) of several important design -patterns. - -@cindex functor -@cindex callback -@cindex smart pointer -The ns-3 code relies heavily on -@emph{Generalized Functors, Callbacks, -Smart Pointers, Singletons, and Object Factories}. Although we will -not assume any detailed knowledge of the idioms and design patterns used -in the ns-3 -system, it will be useful for readers who intend to delve deeply into the -system to understand some important related concepts. We recommend two -resources: @uref{http://www.amazon.com/Design-Patterns-Object-Oriented-Addison-Wesley-Professional/dp/0201633612/,,Design Patterns: Elements of Reusable Object-Oriented Software, Gamma et. al.} and -@uref{http://www.amazon.com/exec/obidos/ASIN/0201704315,,Modern C++ Design: Generic Programming and Design Patterns Applied, Alexandrescu}. - -Gamma addresses the abstract design patterns, and Alexandrescu addresses the -C++ idioms you will often see throughout the ns-3 code. - -@cindex template -Almost any use of ns-3 will require some basic knowledge of C++ -templates. -We will discuss the high-level uses in this tutorial. However, if you venture -deeply into the source code, you will see fairly heavy use of relatively -sophisticated C++ templates in some of low-level modules of the system. The -You don't have to be a template guru to complete this tutorial but if you -expect to work in ns-3 within the simulation core, you will have to be -somewhat fluent -with templates. If you want to truly grok C++ templates we recommend, -@uref{http://www.amazon.com/Templates-Complete-Guide-David-Vandevoorde/dp/0201734842/,,C++ Templates: The Complete Guide, Vandevoorde and Josuttis}. - -@node Socket-Programming -@section Socket Programming - -@cindex sockets -We will assume a basic facility with the Berkeley Sockets API in the examples -used in this tutorial. If you are new to sockets, we recommend reviewing the -API and some common usage cases. For a good overview of programming TCP/IP -sockets we recommend @uref{http://www.elsevier.com/wps/product/cws_home/680765,,Practical TCP/IP Sockets in C, Donahoo and Calvert}. - -There is an associated web site that includes source for the examples in the -book, which you can find at: -@uref{http://cs.baylor.edu/~donahoo/practical/CSockets/}. - -If you understand the first four chapters of the book (or for those who do -not have access to a copy of the book, the echo clients and servers shown in -the website above) you will be in good shape to understand the tutorial. -There is a similar book on Multicast Sockets, -@uref{http://www.elsevier.com/wps/product/cws_home/700736,,Multicast Sockets, Makofske and Almeroth}. -that covers material you may need to understand for the multicast examples. - -@c ======================================================================== -@c Downloading and Compiling -@c ======================================================================== - -@node Downloading and Compiling -@chapter Downloading and Compiling - -@cindex Linux -@cindex Cygwin -@cindex GNU -@cindex toolchain -From this point forward, we are going to assume that the reader is working in -Linux or a Linux emulation environment (Linux, Cygwin, etc.) and has the GNU -toolchain installed and verified. - -@cindex Mercurial -@cindex Waf -We are going to assume that you have Mercurial and Waf installed and running -on the target system as described in the Getting Started section of the -ns-3 web site: @uref{http://www.nsnam.org/getting_started.html}. - -@section Downloading -@cindex tarball -The ns-3 code is available in Mercurial repositories on the server -code.nsnam.org. You can download a tarball, but we recommend working with -Mercurial --- it will make your life easier in the long run. - -@cindex repository -If you go to the following link: @uref{http://code.nsnam.org/}, -you will see a number of repositories. Many are the private repositories of -the ns-3 development team. The repositories of interest to you -will be -prefixed with ``ns-3''. The current development snapshot (unreleased) of -ns-3 may be found at: @uref{http://code.nsnam.org/ns-3-dev/}. - -The developers attempt to keep this repository in a consistent, working state -but it is a development area with unreleased code present, so you may want to -consider downloading an official release. - -There will be a number of released repositories present at code.nsnam.org. -These repos will have names like ns-3.0.1 --- which referes to release 3.0.1 -of the network simulator (or if you like, release 0.1 of ns-3). -Since the releases are changing at a rate of one per month, I will stick with -the more constant ns-3-dev here, but you can replace the string ns-3-dev with -your choice of release (e.g., ns-3.0.5) below. You can find the latest -version of the code either by inspection of the repository list or by going -to the ``Getting Started'' web page and looking for the latest release -identifier. - -One practice is to create a directory called @code{repos} in one's home -directory under which one can keep local Mercurial repositories. -@emph{Hint: we will -assume you do this later in the tutorial.} If you adopt that approach, you -can get a copy of any of the development versions of ns-3 by typing -the following into your Linux shell (assuming you have installed Mercurial): - -@verbatim - cd - mkdir repos - cd !$ - hg clone http://code.nsnam.org/ns-3-dev -@end verbatim - -As the hg command executes, you should see something like the following, - -@verbatim - destination directory: ns-3-dev - requesting all changes - adding changesets - adding manifests - adding file changes - added 1513 changesets with 5687 changes to 733 files - 358 files updated, 0 files merged, 0 files removed, 0 files unresolved -@end verbatim - -After the clone command completes, you should have a directory called -ns-3-dev under your @code{~/repos} directory, the contents of which should -look something like the following: - -@verbatim - AUTHORS RELEASE_NOTES examples/ src/ waf* - LICENSE VERSION ns3/ tutorial/ waf.bat* - README doc/ samples/ utils/ wscript -@end verbatim - -You are now ready to build the ns-3 distribution. - -@section Building -@cindex Waf!build -@cindex Waf!configure -@cindex Waf!debug -@cindex Waf!compile -We use Waf to build the ns-3 project. The first thing you -will need to do is to configure the build. For reasons that will become clear -later, we are going to work with debug builds in the tutorial. To explain to -Waf that it should do debug builds you will need to execute the following -command, - -@verbatim - ./waf -d debug configure -@end verbatim - -This runs the copy of Waf in the local directory (which is provided as a -convenience for you). As the build system checks for various dependencies -you should see output that looks similar to the following, - -@verbatim - ~/repos/ns-3-dev >./waf -d debug configure - Checking for program g++ : ok /usr/bin/g++ - Checking for program cpp : ok /usr/bin/cpp - Checking for program ar : ok /usr/bin/ar - Checking for program ranlib : ok /usr/bin/ranlib - Checking for compiler could create programs : ok - Checking for compiler could create shared libs : ok - Checking for compiler could create static libs : ok - Checking for flags -Wall : ok - Checking for flags -O2 : ok - Checking for flags -g -DDEBUG : ok - Checking for flags -g3 -O0 -DDEBUG : ok - Checking for g++ : ok - Checking for header stdlib.h : ok - Checking for header stdlib.h : ok - Checking for header signal.h : ok - Checking for high precision time implementation: 128-bit integer - Checking for header stdint.h : ok - Checking for header inttypes.h : ok - Checking for header sys/inttypes.h : not found - Configuration finished successfully; project is now ready to build. - ~/repos/ns-3-dev > -@end verbatim - -The build system is now configured and you can build the debug versions of -the ns-3 programs by simply typing, - -@verbatim - ./waf --check -@end verbatim - -You will see many Waf status messages displayed as the system compiles. The -most important is the last one, - -@verbatim - Compilation finished successfully -@end verbatim - -and you will see a number of software unit tests subsequently execute. - -@section Running a Script -@cindex Waf!run -We typically run scripts under the control of Waf. This allows the build -system to ensure that the shared library paths are set correctly and that -the libraries are available at run time. To run a program, simply use the -@code{run} option in Waf. Let's run the ns-3 equivalent of the hello -world program by typing the following: - -@verbatim - ./waf --run hello-simulator -@end verbatim - -Waf first checks to make sure that the program is built correctly and -executes a build if required. Waf then then executes the program, which -produces the following output. - -@verbatim - Hello Simulator -@end verbatim - -If you want to run programs under another tool such as gdb or valgrind, -see this @uref{http://www.nsnam.org/wiki/index.php/User_FAQ#How_to_run_NS-3_programs_under_another_tool,,wiki entry}. - -@emph{Congratulations. You are now an ns-3 user.} - -@c ======================================================================== -@c Some Prerequisites -@c ======================================================================== - -@node Some-Prerequisites -@chapter Some Prerequisites - -The first thing we need to do before actually starting to code is to explain -a few core concepts, abstractions and idioms in the system. Much of this may -appear transparently obvious to some, but we recommend taking the time to read -through this chapter just to ensure you are starting on a firm foundation. - -@section Abstractions - -In this section, we'll review some terms that are commonly used in -networking, but have a specific meaning in ns-3. - -@subsection Node -@cindex Node -In Internet jargon, a computing device that connects to a network is called -a @emph{host} or sometimes an @emph{end system}. Because ns-3 is a -@emph{network} simulator, not specifically an @emph{Internet} simulator, we -intentionally do not use the term host since it is closely associated with -the Internet and its protocols. Instead, we use a more generic term also -used by other simulators that originates in Graph Theory --- the @emph{node}. - -@cindex Node!class -In ns-3 the basic computing device abstraction is called the -node. This abstraction is represented in C++ by the class @code{Node}. The -@code{Node} class provides methods for managing the representations of -computing devices in simulations. Developers are expected to specialize the -@code{Node} in the object-oriented programming sense to create new computing -device models. In this tutorial, we will use a specialization of class -@code{Node} called @code{InternetNode}. As you might expect, the -@code{InternetNode} is a class that represents a host in the Internet sense, -and automatically provides core IPv4 networking protocols. - -You should think of a @code{Node} as a computer to which you will add -functionality. One adds things like applications, protocol stacks and -peripheral cards with their associated drivers to enable the computer to do -useful work. We use the same basic model in ns-3. - -@subsection Application -@cindex Application -Typically, computer software is divided into two broad classes. @emph{System -Software} organizes various computer resources such as memory, processor -cycles, disk, network, etc., according to some computing model. System -software usually does not use those resources to complete tasks that directly -benefit a user. A user would typically run an @emph{application} that acquires -and uses the resources controlled by the system software to accomplish some -goal. - -@cindex system call -Often, the line of separation between system and application software is made -at the privilege level change that happens in operating system traps. -In ns-3 there is no real concept of operating system and especially -no concept of privilege levels or system calls. We do, however, have the -idea of an application. Just as software applications run on computers to -perform tasks in the ``real world,'' ns-3 applications run on -ns-3 @code{Node}s to drive simulations in the simulated world. - -@cindex Application!class -In ns-3 the basic abstraction for a user program that generates some -activity to be simulated is the application. This abstraction is represented -in C++ by the class @code{Application}. The @code{Application} class provides -methods for managing the representations of our version of user-level -applications in simulations. Developers are expected to specialize the -@code{Application} in the object-oriented programming sense to create new -applications. In this tutorial, we will use specializations of class -@code{Application} called @code{UdpEchoClient} and @code{UdpEchoServer}. -As you might expect, these applications compose a client/server application set -used to generate and echo simulated network packets - -@subsection Channel -@cindex Channel - -In the real world, one can connect a computer to a network. Often the media -over which data flows in these networks are called @emph{channels}. When -you connect your Ethernet cable to the plug in the wall, you are connecting -your computer to an Ethernet communication channel. In the simulated world -of ns-3 one connects a @code{Node} to an object representing a -communication channel. Here the basic communication subnetwork abstraction -is called the channel and is represented in C++ by the class @code{Channel}. - -The @code{Channel} class provides methods for managing communication -subnetwork objects and connecting nodes to them. They may also be specialized -by developers in the object oriented programming sense. A @code{Channel} -specialization may model something as simple as a wire. The specialized -@code{Channel} can also model things as complicated as a large Ethernet -switch, or three-dimensional space in the case of wireless networks. - -We will use specialized versions of the @code{Channel} called -@code{CsmaChannel} and @code{PointToPointChannel} in this tutorial. The -@code{CsmaChannel}, for example, models a version of a communication subnetwork -that implements a @emph{carrier sense multiple access} communication medium. -This gives us Ethernet-like functionality. - -@subsection Net Device -@cindex NetDevice -@cindex Ethernet - -It used to be the case that if you wanted to connect a computers to a network, -you had to buy a specific kind of network cable and a hardware device called -(in PC terminology) a @emph{peripheral card} that needed to be installed in -your computer. These cards were called Network Interface Cards, or -@emph{NIC}s. Today most computers come with the network controller hardware -built in and users don't see these building blocks. - -A NIC will not work without a software driver to control the hardware. In -Unix (or Linux), a piece of peripheral hardware is classified as a -@emph{device}. Devices are controlled using @emph{device drivers}, and network -devices (NICs) are controlled using @emph{network device drivers} -collectively known as @emph{net devices}. In Unix and Linux you refer -to these net devices by names such as @emph{eth0}. - -In ns-3 the @emph{net device} abstraction covers both the software -driver and the simulated hardware. A net device is ``attached'' to a -@code{Node} in order to enable the @code{Node} to communicate with other -@code{Node}s in the simulation via @code{Channel}s. Just as in a real -computer, a @code{Node} may be connected to more than one @code{Channel} via -multiple @code{NetDevice}s. - -The net device abstraction is represented in C++ by the class @code{NetDevice}. -The @code{NetDevice} class provides methods for managing connections to -@code{Node} and @code{Channel} objects; and may be specialized by developers -in the object-oriented programming sense. We will use the specialized version -of the @code{NetDevice} called the @code{CsmaNetDevice} in this tutorial. -Just as an Ethernet NIC is designed to work with an Ethernet network, the -@code{CsmaNetDevice} is designed to work with a @code{CsmaChannel}. - -@subsection Topology Helpers -In a real network, you will find host computers with added (or built-in) -NICs. In ns-3 we would say that you will find @code{Nodes} with -attached @code{NetDevices}. In a large simulated network you will need to -arrange many connections between @code{Node}s, @code{NetDevice}s and -@code{Channel}s. - -Since connecting a @code{NetDevice} to a @code{Node}, and a @code{NetDevice} -to a @code{Channel} is such a common task in ns-3 we provide what we -call @emph{topology helpers} to make this as easy as possible. Topology -helpers perform much of the dirty work of creating and connecting net devices. -For example, it may take several distinct method calls to create a NetDevice, -add a MAC address, connect the net device to a @code{Node} and configure -the protocol stack, and then connect the @code{NetDevice} to a @code{Channel}. -We use topology helper functions to compose those distinct operations into -an easy to use model. - -Topology helper functions use the abstractions (described above) of Network -Interface Cards and Cables. When you think of adding a new kind of network, -you may think of going out to the local computer retailer and buying a kit. -This kit might include a network cable and some number of peripheral cards and -their associated software drivers. You can think of topology helpers in -roughly the same way. Instead of buying a kit for a given type of network, -you will use a topology helper class for a given type of network, to accomplish -the equivalent of installing the network ``kit.'' - -@section Important Idioms -Now that we have identified that there are C++ classes in the system called -@code{Node} and @code{InternetNode}, we need to understand how to bring -objects of these classes into existence, and manage their lifetimes. Let's -examine this in some detail here. - -@cindex InternetNode -@cindex CreateObject -@cindex Ptr -In ns-3, if we want to create an @code{InternetNode} in a -script, we will -typically do something like the following example: - -@verbatim - Ptr p = CreateObject (); -@end verbatim - -@cindex smart pointer -To some, it may seem intuitively obvious that we're creating an -@code{InternetNode} object and assigning responsibility for managing the -object to a smart pointer named @code{p}. For the rest of us, there may be -a lot in that line that is unfamiliar, so let's look at what this line means -in some detail. - -@subsection Templates 101 -@cindex template -If you are familiar with C++ templates, you may skip this section as it is -just a cursory introduction to function and class templates. - -Referring back to the example line of code, reproduced below for your -convenience, the angle brackets you see in the code indicate that we are -using C++ @emph{templates}. - -@verbatim - Ptr p = CreateObject (); -@end verbatim - -The purpose of templates is to allow a programmer to write one version of code -that is applicable over multiple types. Some people consider templates to be -an enhancement of the C preprocessor macro functionality. At some level -this comparison reveal some similarities, but C++ templates are really -quite different. - -@cindex template!declaration -@cindex template!definition -@cindex template!use -In C++, just as with most language constructs, templates are @emph{declared}, -@emph{defined} and @emph{used}. A declaration of a template might look -something like, - -@verbatim - template T Add (T first, T second); -@end verbatim - -@cindex template!typename -This line uses the keyword @code{template} followed by a declaration of a -type name (in this case @code{T}) in angle brackets. The angle brackets -should indicate to you that a template is being declared, defined or used. -The type name @code{T} can be thought of as a string that will be substitited -during the use phase of the template. For example, the @code{T} may be -replaced by the word @code{int}. It is this substitution that leads people -to compare templates with macros. - -Without going into too much more detail, this snippet declares that a piece -of code exists that will be able to call a function @code{Add} that will -add arbitrary types together. The @code{T} will be eventually replaced by -a C++ data type name. For example, - -@verbatim - T Add (T first, T second); -@end verbatim - -might eventually become - -@verbatim - int Add (int first, int second); -@end verbatim - -If the template has been declared, we need to @emph{define} what that piece of -code will actually do. That might look something like, - -@verbatim - template - T Add (T first, T second) - { - return first + second; - } -@end verbatim - -All we've done here is to provide an implementation of the template that -adds the two variables together and returns the result. Note that this -implementation works for any type that provides an @code{operator+}. - -The puzzle all comes together when you understand that @emph{using} a template -causes the compiler to automatically instantiate code for a specific function -according to the given template parameters. You might use the above template -like, - -@verbatim - int x, y, z; - z = Add (x, y); -@end verbatim - -@cindex template!instantiate -When the compiler sees @code{Add} it understands that it needs to make -sure that code is instantiated (created) to perform the @code{Add} using the -specified type @code{}. To a first approximation, the compiler will -replace the typename @code{T} with the specified type @code{int} and -automagically generate code equivalent to, - -@verbatim - int Add (int first, int second) - { - return first + second; - } -@end verbatim - -A user of the template definition could just as easily have provided a use -that assigned the type float. This would simply be done like, - -@verbatim - float x, y, z; - z = Add (x, y); -@end verbatim - -In this case, the compiler would automatically generate code that looked like, - -@verbatim - float Add (float first, float second) - { - return first + second; - } -@end verbatim - -@cindex template!function -This particular kind of template programming uses what are called -@emph{function templates}. They are called function templates since you -are @emph{templating} function declarations and definitions. - -@cindex template!class -Templates can also be used in conjunction with classes, in which case you are -said to be using, not too surprisingly, @emph{class templates}. The syntax and -use is similar. To declare a class template you might use something like, - -@verbatim - template - class MyStack - { - void Push (T data); - T Pop (void); - }; -@end verbatim - -The methods can be defined separately in a method similar to function template -definitions, - -@verbatim - template void MyStack::Push (T data) - { - ... - }; -@end verbatim - -You can then use the new templated class in the following way, - -@verbatim - int x, y; - - MyStack stack; - stack.Push (x); - y = stack.Pop (); -@end verbatim - -Similarly to the function template case, the compiler knows that it has to -automatically generate code to fill out the class and method declarations -and definitions using the appropriate type specified by @code{}. - -@node Smart Pointers 101 -@subsection Smart Pointers 101 -If you are familiar with C++ smart pointers, you may skip this section as it -is just a cursory introduction to smart pointers and intrusive reference -counting. - -@cindex smart pointer -Referring back to the example line of code, partially reproduced below for -your convenience below, the left hand side is the declaration and -initialization of a class template that implements a @emph{smart pointer}. - -@verbatim - Ptr p = ... -@end verbatim - -To a first approximation, you can think of @code{Ptr} as the a new kind -of declaration of a pointer to a @code{Node} object. The difference is that -a smart pointer is a user-defined data type (instantiated via a templated -class) that @emph{simulates} a classical pointer but provides additional -features. As an aside, you typically pronounce @code{Ptr} as -``pooter node'' where pooter rhymes with footer. - -@cindex memory management -One of the most important ``additional feature'' provided by smart pointers is -automatic memory management. Since you now understand class templates, you -will understand how the template allows us to write the pointer code once, but -allows us to point to many different kinds of objects. Later in the tutorial -you will see variations such as @code{Ptr} and @code{Ptr}, -which are smart pointers to an IP version 4 object and a channel object, -respectively. - -The use of built-in pointers in C and C++ is a major source of bugs. Constant -allocation of, passing of responsibility for, and deallocation of underlying -data makes it very likely that errors will occur. In one of these errors, -the usual problem is that the responsibility for deallocating a memory block -is misplaced. This may result in a memory leak or a duplicate deallocation. -Smart pointers try to prevent this kind of problem by working with the -@emph{scope} and @emph{extent} rules of the language to make memory -deallocation automatic. - -The scope of a variable defines where in a program a given variable may be -referred to. The extent of a variable defines when in the program's execution -the variable has a valid value. Consider a simple subroutine that contains a -smart pointer. - -@verbatim - void SimpleSubroutine (void) - { - Ptr p; - } -@end verbatim - -@cindex scope -The variable named @code{p} has a scope limited to the subroutine itself. The -variable is said to @emph{come into scope} as the subroutine is entered during -execution. At this time, the constructor of the underlying class is executed -and a valid variable is available for use. When the subroutine is done -executing, the variable is said to @emph{go out of scope}. This causes the -destructor of the underlying class to be executed and the variable no longer -has a valid value. This is not a problem since it is no longer valid to refer -to the parameter. Smart pointers take advantage of these defined actions at -points where variables must be valid and become discardable to determine when -underlying data can be freed. - -@cindex reference counting!intrusive -The ns-3 smart pointer mechanism uses a mechanism called intrusive -reference counting to determine when a memory block should be automatically -deallocated. The term ``intrusive'' means that a reference count (a count of -variables required to have valid data) is stored in the object being managed -instead of in a proxy object. This means that each piece of memory managed by -a ns-3 smart pointer includes a reference count. When a smart -pointer to a reference counted object is created, this reference count is -incremented. This indicates that a new variable requires a valid data object -be present. When a smart pointer to a reference counted object is destroyed -(for example, when going out of scope) the reference count of the managed -object is decremented. When the reference count goes to zero it means that -all smart pointers to the underlying object have gone out of scope and the -object is no longer needed by any past ``users'' of the object. This in turn -means that the object can be safely deallocated, and this is done -automatically for you as the ``last'' smart pointer goes out of scope. - -Consider how this might work as you pass a smart pointer to an object down -a protocol stack. At each level of the stack, you pass the smart pointer -by value. This causes a copy of the smart pointer to be made, which -increments the reference count of the underlying object. When the -@emph{calling} method is done executing, the calling smart pointer goes out of -scope and the reference count is decremented. This leaves the single smart -pointer in the @emph{called} method with a reference to the underlying object. -When the smart pointer in the called method goes out of scope, the destructor -for the smart pointer is called. The destructor checks the reference count -of the underlying object and sees that it becomes zero. This indicates that -the object can be deallocated, and the destructor does so. This results in -the lifetime management of the underlying object being automatically managed, -a boon if you have experience with ``manual'' memory management and finding -memory leaks. - -Now, we want to make this feature available as widely as possible to objects -in the ns-3 system. The basic operations of the smart pointer class -are the same across any intrusively reference counted object. C++ provides a -mechanism to achieve this kind of generic behavior --- the template. Let's -examine the declaration of the smart pointer in more detail. First consider -the way you might declare and use a built-in pointer. For the sake of -simplicity, just assume that a C++ object of the class @code{MyClass} exists. -Further assume that @code{MyClass} provides one method called @code{method}. -Using built-in pointers, you could do something like the following: - -@verbatim - MyClass *p = ... - p->method (); -@end verbatim - -@cindex smart pointer -One of the key design points of smart pointers is that they should simulate -built-in pointers. In C++ this is done by overloading @code{operator->}, -@code{operator=} and @code{operator*}. To implement a smart pointer we need -to provide a generic class that implements these operators. This generic -class should allow operations that appear as if it were a built-in pointer -to the reference counted object. Typically this is accomplished via a -relatively simple C++ class template. If you are interested in the details -of how this may be accomplished, see Alexandrescu for a good treatment, - -@cindex template -Taking the template as given, in order to declare a smart pointer you will -need to create a smart pointer object and provide the template parameter -needed to instantiate the required code. This parameter will be the name -of the reference counted class to which you want to point. The smart -pointer class overrides @code{operator=} which allows initialization of the -smart pointer just as if it were a built-in pointer. The end result is that -you use smart pointers just as if they were built-in pointers: - -@verbatim - SmartPointer p = ... - p->method (); -@end verbatim - -@node Object Creation -@subsection Object Creation -@cindex CreateObject -On the right hand side of the line of code we're examining (reproduced below -for convenience) is the creation of an @code{InternetNode} object. - -@verbatim - ... = CreateObject (); -@end verbatim - -@cindex template!function -This turns out to be an instance of use of a C++ @emph{function template}. The -definition of the @code{CreateObject()} template calls the new -operator to create an object of the type T. It then creates a new smart -pointer of the appropriate type (i.e., @code{Ptr}). This new smart -pointer is assigned initial responsibility for the new object which has its -reference count set to one. - -Since the underlying creation mechanism is via the @code{new} operator, and -you can pass parameters to the constructor for an object, we provide several -templates that you can use for passing parameters to the object constructors. -If the constructor for the object requires a parameter, you simply pass that -parameter to the @code{Create} function like this, - -@verbatim - int parm = 1; - ... = CreateObject (parm); -@end verbatim - -We provide Create templates with up to seven parameters, so you could -conceivably use the @code{Create} template in situations such as, - -@verbatim - int parm = 1; - ... = CreateObject (p1, p2, p3, p4, p5, p6, p7); -@end verbatim - -@subsection Type Safety -Lets take one final look at the now infamous example line of code that we -have been examining for some time (again reproduced below). - -@verbatim - Ptr p = CreateObject (); -@end verbatim - -@cindex smart pointer -@cindex Node -@cindex Create -You may have noticed that the smart pointer on the left hand side of the -assignment is associated with the type @code{Node} and the @code{Create} -template on the right hand side creates an @code{InternetNode} object and -returns a @code{Ptr} smart pointer. For this assignment of a -@code{Ptr} to a @code{Ptr} to work, there must be some -kind of type conversion going on. - -@cindex implicit conversion -Many programmers use @code{implicit conversions} without even realizing it -since they are sometimes so intuitive. For example, in the following code, - -@verbatim - int i = 1; - double d = 2.; - if (n == d) ... -@end verbatim - -@cindex standard conversion -the integer (1) is implicitly converted to a double (1.) before the comparison -takes place. This conversion is performed using what is known as a C++ -@emph{standard conversion}. There are a number of standard conversions defined -by the C++ standard. Among them are, - -@itemize @bullet -@item Integral Promotions -@item Integral Conversions -@item Floating Conversions -@item Pointer Conversions -@item Reference Conversions -@end itemize - -@cindex assignment operator -@cindex Ptr -For the case of interest here, we need to know what happens in the -assignment operator (@code{operator=}) of our smart pointer @code{Ptr}. -This operator takes a reference to a @code{Ptr} and not a reference to -a @code{Ptr}. The one situation where this works automatically -in C++ is if the ``destination'' reference is to a visible, unambiguous base -class of the ``source'' reference. In this case, the underlying pointer is -@emph{cast} from one type to the other automatically. - -To summarize: The magic happens in the assignment operator. Class -@code{InternetNode} inherits from class @code{Node}. The reference to the -@code{InternetNode} object in question is, in essence, a pointer to an -@code{InternetNode} object. The @code{InternetNode} class inherits from the -@code{Node} base class in a way that makes @code{Node} visible and unambiguous. -Therefore, there exists a standard conversion from an @code{InternetNode *} -to a @code{Node *} and by extension from an @code{InternetNode &} to a -@code{Node &}. This conversion is applied automatically (and invisibly) -during parameter passing in the assignment operator we are examining. - -@cindex base class -This is a rather involved way of saying there's an invisible pointer cast -to a base class happening in the assignment. That means that - -@verbatim - Ptr p = CreateObject (); -@end verbatim - -or, - -@verbatim - Ptr p = CreateObject (); -@end verbatim - -will work just fine. Of course, if you try something @emph{bad} (TM), like: - -@verbatim - Ptr p = CreateObject (); -@end verbatim - -the compiler will quite appropriately complain that there is no conversion -between these completely unrelated objects (CsmaChannel and Node). - -@subsection Summary -Going back to our infamous first line of ns-3 code, we said that if -we want to create an InternetNode in a script, we will typically do something -like: - -@verbatim - Ptr p = CreateObject (); -@end verbatim - -@cindex Create -@cindex InternetNode -@cindex smart pointer -Now we know that this is really a simple statement. We create an -@code{InternetNode} object on the heap (indirectly using operator @code{new} -and passing no parameters to its constructor) and assign responsibility for -managing the new object's lifetime to a smart pointer. This smart pointer is -a pointer to a @code{Node} object, so there was a hidden cast from -@code{InternetNode} to a @code{Node} done via a standard C++ conversion. - -This may have been quite a hurdle to get past that first line of code, but -we have covered quite a few of the important idioms that you'll encounter in -this tutorial. - -@c ======================================================================== -@c A First ns-3 script -@c ======================================================================== - -@node A-First-ns-3-Script -@chapter A First ns-3 script -@cindex design pattern -@cindex idiom -Lets build a simple network using the ns-3 design patterns, idioms, -classes and helpers we have just looked at. If you downloaded the system as -was suggested above, you will have a release of ns-3 in a directory -called @code{repos} under your home directory. Change into that directory, -where you should see a directory structure something like the following. - -@verbatim - AUTHORS RELEASE_NOTES examples/ src/ waf* - LICENSE VERSION ns3/ tutorial/ waf.bat* - README doc/ samples/ utils/ wscript -@end verbatim - -@cindex hello-simulator.cc -Change into the tutorial directory. You should see a file named -@code{hello-simulator.cc} located there. Copy this file into one named -@code{simple.cc}. If you open this new file in your favorite editor you will -see some copyright information and the following C++ code: - -@verbatim - #include "ns3/log.h" - - NS_LOG_COMPONENT_DEFINE ("HelloSimulator"); - - using namespace ns3; - - int - main (int argc, char *argv[]) - { - LogComponentEnable ("HelloSimulator", LOG_LEVEL_INFO); - - NS_LOG_INFO ("Hello Simulator"); - } -@end verbatim - -This is the ns-3 version of the ubiquitous hello-world program. It -uses the ns-3 Log module to print ``Hello Simulator'' into the - standard error output stream. - -@cindex logging -Log components are named objects that provide for controlling the verbosity of -debugging output in the system. We'll have a lot more to say about logging -later on, but for now you can just consider the macro @code{NS_LOG_INFO} to be -a kind of fancy printf to the standard error. - -@section A Simple Network -@cindex InternetNode -Let's create a simple network of @code{InternetNode} elements. In order to -actually create an @code{InternetNode}, you will have to include some header -files. Put the following code after the include statement in @code{simple.cc}. - -@verbatim - #include "ns3/ptr.h" - #include "ns3/internet-stack.h" -@end verbatim - -@cindex include files -The ns-3 build system places the core include files it needs into a -directory called @code{ns-3} and so whenever you need to include one of the -core files you need to explicitly code this. The file @code{ptr.h} defines -the generic smart pointer that we use. The file @code{internet-stack.h} -defines the class InternetNode which, as described above, represents an IP -version 4-based computing element in the simulator. - -So let's create a few new @code{InternetNode}s by adding the following lines -of code after the call to @code{NS_LOG_INFO} in the simple.cc file right -after the call to @code{NS_LOG_INFO}. - -@verbatim - Ptr n0 = CreateObject (); - Ptr n1 = CreateObject (); - Ptr n2 = CreateObject (); - Ptr n3 = CreateObject (); -@end verbatim - -As we now understand, this will create four @code{InternetNode} objects on -the heap and create four @code{Ptr} smart pointer objects on the stack -to manage them. You should remember that by using the smart pointers you are -freed from the responsibility to delete the objects you assign to them. - -@cindex Channel -@cindex CsmaChannel -The next step is to create a channel over which these nodes can communicate. -Let's use the CsmaChannel and create a local area network that will allow us -to hook up nodes similarly to an Ethernet. - -As usual, we'll need to include the file that provides the appropriate class -declarations: - -@verbatim - #include "ns3/csma-channel.h" -@end verbatim - -Next, Add the following line of code (typically done after node creation) to -create a channel with a five megabit per second data rate and a two -millisecond speed-of-light delay between all nodes. The idiom for creating -the channel is similar to that of the node, but the actual @code{Create} -function is hidden from us in the topology code. Observe that we are -using a Csma topology helper function to free us from the details regarding -how the Carrier Sense Multiple Access Channel is actually brought into -existence and initialized. - -@verbatim - Ptr lan = - CsmaTopology::CreateCsmaChannel (DataRate (5000000), MilliSeconds (2)); -@end verbatim - -@cindex idiom!unnamed parameter -You may be unfamiliar with the @emph{unnamed parameter} idiom used here. -When added to a list of parameters, the code @code{DataRate (5000000)} -constructs a DataRate object on the stack using the appropriate constructor. -The resulting object has no name, and therefore cannot be referenced -elsewhere, but is passed to the callee method where it has a valid name and -can be used. This idiom is essentially a shorthand version of the following: - -@verbatim - DataRate rate (5000000); - Time latency (MilliSeconds (2)); - Ptr lan = CsmaTopology::CreateCsmaChannel (rate, latency); -@end verbatim - -@cindex constructor -@cindex constructor!Time -We should pause for a moment and discuss the constructor to the @code{Time} -data type. There are a number of different constructors for these objects, and -so there are a number of ways that this initialization could have been done. -There is a constructor that takes a string argument, consisting of expressions -using the units @code{s, ms, us, ns, ps} or @code{fs}, so this could have been -written, - -@verbatim - Time latency ("2ms"); -@end verbatim - -There are also helper functions available that create time units (one of these -was used in the example): - -@itemize @bullet -@item @code{Seconds (double)} -@item @code{MilliSeconds (uint64_t)} -@item @code{MicroSeconds (uint64_t)} -@item @code{NanoSeconds (uint64_t)} -@item @code{PicoSeconds (uint64_t)} -@item @code{FemtoSeconds (uint64_t)} -@end itemize - -C++ will attempt to promote parameters appropriately, but you will typically -see constructions that respect the type correctness of the constructor, as -in @code{Seconds (1.)} and @code{MilliSeconds (2)}. Notice that the code -@code{Seconds (1)} will work just as well as @code{Seconds (1.)} since the -integer 1 will be automatically promoted to a double 1. in the former code. -The converse will not work --- i.e., you cannot write code that says -@code{MilliSeconds (2.)} since a @emph{type demotion} would be required that -could lose information and the compiler will not do such things ``behind your -back.'' Don't be thrown off by this kind of automatic conversion. - -@cindex MAC!address -Okay, now we have code to create four nodes and a local area network. The -next step is to wire the network together. We do this by adding net devices -to the node. When we add the net device, we also specify the network to which -the net device is connected and provide a MAC address appropriate to the -device and network types. Since we're creating an IP version 4 network using -a Csma channel, you may expect that we'll be using topology helpers -appropriate to those types --- the CsmaIpv4Topology helper. As you may expect, -we'll need to include some files to get the appropriate definitions: - -@verbatim - #include "ns3/mac48-address.h" - #include "ns3/csma-net-device.h" - #include "ns3/csma-topology.h" - #include "ns3/csma-ipv4-topology.h" -@end verbatim - -Now, all that is left is to do the ``wiring'': - -@verbatim - uint32_t nd0 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n0, lan, - Mac48Address("08:00:2e:00:00:00")); -@end verbatim - -[Note the additional unnamed parameter idiom usage here.] - -This code calls the topology helper relating to Csma channels and IP version -four nodes. It asks to install a Csma net device ``into'' node zero -(@code{n0}) connecting the device to the channel named (@code{lan}). It also -assigns a MAC address to the net device. You can add similar lines of code -connecting the other nodes to the lan (remembering to assign new MAC -addresses). - -@verbatim - uint32_t nd1 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n1, lan, - Mac48Address("08:00:2e:00:00:01")); - - uint32_t nd2 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n2, lan, - Mac48Address("08:00:2e:00:00:02")); - - uint32_t nd3 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n3, lan, - Mac48Address("08:00:2e:00:00:03")); -@end verbatim - -@cindex IP!address -@cindex IP!network mask -@cindex multihome -Finally, we need to add IP addresses to our nodes. The pointers to the -nodes are stored in n0, n1, n2 and n3. We added net devices to each of -the nodes and remembered the net device index numbers as nd0, nd1, nd2 and -nd3. You can add multiple net devices to each node resulting in a situation -similar to a multi-homed host. Each time you add a net device, you will get -a new index. Since the IP address for a multi-homed host is associated with -a net device, we need to provide that index (which we have saved) to the -topology helper. We provide an IP version four address via the ns-3 -class @code{Ipv4Address} which takes a dotted decimal string as a constructor -parameter. We also provide a network mask using the ns-3 class -@code{Ipv4Mask} which also takes a dotted decimal string. The code to -perform the IP address assignment, then, looks like the following: - -@verbatim - CsmaIpv4Topology::AddIpv4Address (n0, nd0, Ipv4Address ("10.1.1.1"), - Ipv4Mask ("255.255.255.0")); - - CsmaIpv4Topology::AddIpv4Address (n1, nd1, Ipv4Address ("10.1.1.2"), - Ipv4Mask ("255.255.255.0")); - - CsmaIpv4Topology::AddIpv4Address (n2, nd2, Ipv4Address ("10.1.1.3"), - Ipv4Mask ("255.255.255.0")); - - CsmaIpv4Topology::AddIpv4Address (n3, nd3, Ipv4Address ("10.1.1.4"), - Ipv4Mask ("255.255.255.0")); -@end verbatim - -We have now constructed a simulated network. Your code should now look -something like the following, - -@verbatim - #include "ns3/log.h" - #include "ns3/ptr.h" - #include "ns3/internet-stack.h" - #include "ns3/csma-channel.h" - #include "ns3/mac48-address.h" - #include "ns3/csma-net-device.h" - #include "ns3/csma-topology.h" - #include "ns3/csma-ipv4-topology.h" - - NS_LOG_COMPONENT_DEFINE ("HelloSimulator"); - - using namespace ns3; - - int - main (int argc, char *argv[]) - { - LogComponentEnable ("HelloSimulator", LOG_LEVEL_INFO); - - NS_LOG_INFO ("Hello Simulator"); - - Ptr n0 = CreateObject (); - Ptr n1 = CreateObject (); - Ptr n2 = CreateObject (); - Ptr n3 = CreateObject (); - - Ptr lan = - CsmaTopology::CreateCsmaChannel (DataRate (5000000), MilliSeconds (2)); - - uint32_t nd0 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n0, lan, - Mac48Address("08:00:2e:00:00:00")); - - uint32_t nd1 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n1, lan, - Mac48Address("08:00:2e:00:00:01")); - - uint32_t nd2 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n2, lan, - Mac48Address("08:00:2e:00:00:02")); - - uint32_t nd3 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n3, lan, - Mac48Address("08:00:2e:00:00:03")); - - CsmaIpv4Topology::AddIpv4Address (n0, nd0, Ipv4Address ("10.1.1.1"), - Ipv4Mask ("255.255.255.0")); - - CsmaIpv4Topology::AddIpv4Address (n1, nd1, Ipv4Address ("10.1.1.2"), - Ipv4Mask ("255.255.255.0")); - - CsmaIpv4Topology::AddIpv4Address (n2, nd2, Ipv4Address ("10.1.1.3"), - Ipv4Mask ("255.255.255.0")); - - CsmaIpv4Topology::AddIpv4Address (n3, nd3, Ipv4Address ("10.1.1.4"), - Ipv4Mask ("255.255.255.0")); - } -@end verbatim - -This script won't actually do anything yet. The next trick will be to -convince our nodes to try and send some data over the network. - -@section Using Applications -@cindex Create -As mentioned above, we use @code{Application}s in ns-3 to generate -the data used to drive simulations. An @code{Application} is added to a -ns-3 node conceptually just as if you would add an application to a -computer. When an application is created (using the @code{Create} template) -we tell the application which @code{Node} it belongs to (and therefore on -which node it is running) by passing a smart pointer to that @code{Node} in -the constructor arguments. - -@subsection A UDP Echo Client Application -To use an application, we first have to load the header file in which it is -defined. For the UDP echo client, this would mean adding the line, - -@verbatim -#include "ns3/udp-echo-client.h" -@end verbatim - -In order to create the UDP echo client application we will need to add the -following code: - -@verbatim - uint32_t packetSize = 1024; - uint16_t port = 7; - uint32_t maxPacketCount = 1; - Time interPacketInterval = Seconds (1.); - - Ptr client = CreateObject (n0, "10.1.1.2", - port, maxPacketCount, interPacketInterval, packetSize); -@end verbatim - -@cindex packet -The first four lines have broken out the configuration parameters for the -application as named parameters for clarity. We are telling the application -to generate 1024 byte packets (@code{packetSize = 1024}); and to send these -packets to port 7 (@code{port = 7;}). The application is told to send at most -one packet (@code{maxPacketCount = 1;}); and to delay for one second between -packet sends (@code{interPacketInterval = Seconds(1.)}) which is not used since -only one packet is sent. We will defer addressing the type @code{Time} until -we discuss the simulator engine. For now just understand the semantics are -to wait for one second. - -The code to actually create the @code{UdpEchoClient} application uses the -same creation idiom as we have used previously. Notice that we have a case -where the @code{Create} template is used to pass parameters to the constructor -of the underlying object. - -@cindex implicit conversion sequence -Notice that a string is passed as the second parameter. The formal parameter -to the constructor of the @code{UdpEchoClient} object is actually an -@code{Ipv4Address}. We get away with this since C++ allows what are called -@emph{implicit conversion sequences} to occur between the argument in the -function call and the corresponding parameter in the function declaration. -Basically, C++ will try to figure out a way to convert parameters for you -transparently. - -In this case the conversion sequence is based on the constructor for the -Ipv4Address that takes a @code{char const *} as a parameter. C++ notices -that @code{"10.1.1.2"} refers to a @code{char const *} and knows that it -needs to get from there to an @code{Ipv4Address}. The compiler notices that -there is an @code{Ipv4Address} constructor that takes a @code{char const *} -and so it uses that constructor transparently to arrange for the conversion. - -You therefore have several options for passing this value. You can use an -explicit named variable as in the following: - -@verbatim - Ipv4Address addr ("10.1.1.2"); - ... - - Ptr client = CreateObject (n0, addr, port, - maxPacketCount, interPacketInterval, packetSize); -@end verbatim - -@cindex idiom|unnamed parameter -You can use the unnamed parameter idiom that we have previously seen: - -@verbatim - Ptr client = CreateObject (n0, - Ipv4Address ("10.1.1.2"), port, maxPacketCount, interPacketInterval, - packetSize); -@end verbatim - -Or you can rely on implicit conversion sequences as we just saw: - -@verbatim - Ptr client = CreateObject (n0, "10.1.1.2", - port, maxPacketCount, interPacketInterval, packetSize); -@end verbatim - -Which approach to take is a matter of style, really, and you will probably -see all three approaches taken in the ns-3 code. You should be -comfortable seeing and using all three methods. - -@subsection A UDP Echo Server Application -As usual, to use the UDP echo server we need to add a line to define the -application: - -@verbatim -#include "ns3/udp-echo-server.h" -@end verbatim - -In order to create the UDP echo server application we will need to add the -following code: - -@verbatim - Ptr server = CreateObject (n1, port); -@end verbatim - -We only need to tell the application which node to reside on and which port -to listen on for UDP packets. The code to actually create the -@code{UdpEchoServer} application uses the now quite familiar ns-3 object -creation idiom. - -@subsection A UDP Echo Client-Server Simulation -Now we're getting somewhere. Your code should look something like the -following (let's change the log component name and program banner from -``Hello Simulator''to something more descriptive while we're at it). - -@verbatim - #include "ns3/log.h" - #include "ns3/ptr.h" - #include "ns3/internet-stack.h" - #include "ns3/csma-channel.h" - #include "ns3/mac48-address.h" - #include "ns3/csma-net-device.h" - #include "ns3/csma-topology.h" - #include "ns3/csma-ipv4-topology.h" - #include "ns3/udp-echo-client.h" - #include "ns3/udp-echo-server.h" - - NS_LOG_COMPONENT_DEFINE ("UdpEchoSimulation"); - - using namespace ns3; - - int - main (int argc, char *argv[]) - { - LogComponentEnable ("UdpEchoSimulation", LOG_LEVEL_INFO); - - NS_LOG_INFO ("UDP Echo Simulation"); - - Ptr n0 = CreateObject (); - Ptr n1 = CreateObject (); - Ptr n2 = CreateObject (); - Ptr n3 = CreateObject (); - - Ptr lan = - CsmaTopology::CreateCsmaChannel (DataRate (5000000), MilliSeconds (2)); - - uint32_t nd0 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n0, lan, - Mac48Address("08:00:2e:00:00:00")); - - uint32_t nd1 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n1, lan, - Mac48Address("08:00:2e:00:00:01")); - - uint32_t nd2 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n2, lan, - Mac48Address("08:00:2e:00:00:02")); - - uint32_t nd3 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n3, lan, - Mac48Address("08:00:2e:00:00:03")); - - CsmaIpv4Topology::AddIpv4Address (n0, nd0, Ipv4Address ("10.1.1.1"), - Ipv4Mask ("255.255.255.0")); - - CsmaIpv4Topology::AddIpv4Address (n1, nd1, Ipv4Address ("10.1.1.2"), - Ipv4Mask ("255.255.255.0")); - - CsmaIpv4Topology::AddIpv4Address (n2, nd2, Ipv4Address ("10.1.1.3"), - Ipv4Mask ("255.255.255.0")); - - CsmaIpv4Topology::AddIpv4Address (n3, nd3, Ipv4Address ("10.1.1.4"), - Ipv4Mask ("255.255.255.0")); - - uint32_t packetSize = 1024; - uint16_t port = 7; - uint32_t maxPacketCount = 1; - Time interPacketInterval = Seconds (1.); - - Ptr client = CreateObject (n0, "10.1.1.2", - port, maxPacketCount, interPacketInterval, packetSize); - - Ptr server = CreateObject (n1, port); - - } -@end verbatim - -@section Using the Simulation Engine -@cindex model -@cindex simulation executive -You could say that the heart of the ns-3 system is the -@emph{simulation engine} (sometimes called the simulation executive in other -systems). - -In a computer simulation, a computer @emph{model} of a real world @emph{system} -is constructed. This is typically done to minimize cost since you do not have -to actually buy, install and maintain physical hardware. In the case of -ns-3, a model is a representation of a networking component that is -designed to imitate some number of important behaviors or characteristics of -an actual component in a real network. A system is a collection of models -arranged for the purpose of analyzing some behavior. - -@section Models -@cindex CsmaNetDevice -@cindex CsmaChannel -@cindex InternetNode -@cindex NIC -@cindex CSMA -We have already encountered several ns-3 models without specifically -calling them so. The @code{InternetNode}, @code{CsmaNetDevice} and -@code{CsmaChannel} objects are models of an Internet computing node, a CSMA -network interface card (NIC), and a network cable able to move data to and -from other CSMA NICs. - -@cindex model -@cindex CSMA/CD -It is important to note that the @code{Csma} net devices and the @code{Csma} -channel do not correspond to any real world hardware that you can actually go -out and buy. These models implement an approximation, or subset, of the -behaviors that a real CSMA/CD network would have. In this case, the -@code{CsmaNetDevice} does not simulate collision detection (CD). It does -implement carrier sense and performs collision @emph{avoidance} using global -spatial knowledge available in the channel. This would be impossible in any -channel residing in our universe. - -@cindex Ethernet -No model will fully implement @emph{all} of the behaviors of a piece of -hardware. It is important to understand what is being modeled by the -ns-3 components you are using and what is not. For example, the Csma -components we use in this tutorial model a highly abstract multiple access -network that is topologically equivalent to an Ethernet. It is not necessarily -true that results found in a simulation using the Csma models will apply to -a real-world Ethernet network. You must understand what behaviors are -simulated in each of the models before trusting that any results can be -associated with real-world systems. - -@section Time, Events and Callbacks -@cindex time -@cindex event -In a @emph{discrete event simulator} time is not something that @emph{flows}, -nor is it something to be measured --- it is the driving force behind the -progress of the simulation. Time is progressed forward by the simulation -engine and anything that happens in the simulation is ultimately caused by -an @emph{event}. An event is some action in the system that is -@emph{scheduled} to happen at a certain time by the simulation engine. Time -does not flow continuously but steps discretely (in possibly large jumps) -from one scheduled event to another. - -@cindex packet -For example, to start the flow of a packet through the system, one would have -to schedule an event with the simulation engine @emph{before} the simulation -was started. This is important since the simulation engine only jumps time -forward if there is a next event to process. The simulation stops if there -are no more events, which is equivalent to a state where there is ``nothing -more to do.'' Before the simulation starts, one schedules driving events in -terms of absolute time. For example, one could schedule an event to start -the flow of a first packet at, say, ten simulated seconds. In this case, the -simulation would start its clock at zero seconds and look for the first event -in its @emph{event queue}. It would immediately jump time forward by ten -seconds and @emph{fire} the scheduled event --- that is, make the event happen. - -@cindex functor -@cindex function object -@cindex callback -@cindex Callback -In ns-3 an event is basically a pre-packaged function call called a -@emph{functor}. Functors are also known as @emph{function objects}, which is -a more descriptive term --- an object (in the object-oriented programming -sense) that can be called as if it was a function. Typically one uses a -functor to implement @emph{deferred execution} of a function or method. The -most commonly encountered form of deferred execution is in a @emph{callback} -from an I/O system. In this case, the goal would be to start an I/O -operation and return immediately, without having to wait for the operation -to complete. One asks the I/O subsystem to notify you when an operation is -complete by calling some function you provide. This provided function is -known as a callback function. [Imagine calling someone on the telephone and -asking them to do something for you. You also ask them to @emph{call you back} -when they are done.] Events in the ns-3 system work conceptually -the same way, except that instead of an I/O completion driving the process, -the arrival of some simulated time drives the process. The ns-3 -deferred execution mechanism is via a class called @code{Callback}. - -@cindex Time -@cindex Callback -The internal details of the classes representing @code{Time} and -@code{Callback} abstractions will be introduced as required. We won't see -events directly for some time, but you should know that they are happening -``under the sheets'' of the simulations you will be writing. - -@section Driving the Simulation -@cindex Application -As mentioned previously, time is the driving force behind the progress of -a ns-3 simulation. Events are scheduled to happen at certain times -by calling methods of the simulation engine, either directly or indirectly -through, for example, an @code{Application}. - -In order to get the simulation engine set up and running in our code, we must -first include the language definitions required to describe time- and -simulator-specific classes: - -@verbatim - #include "ns3/simulator.h" - #include "ns3/nstime.h" -@end verbatim - -@cindex Application -As we have seen, we need to ``seed'' the simulation with at least one event. -In the case of an @code{Application}, a method to do this is provided. This -method must be implemented by each specialization of the class and we must -call this method in our script before the simulation starts. We can also -provide an event (indirectly) to stop the output of the application at a -certain time. This is done by adding the following lines to our script: - -@verbatim - server->Start(Seconds(1.)); - client->Start(Seconds(2.)); - - server->Stop (Seconds(10.)); - client->Stop (Seconds(10.)); -@end verbatim - -@cindex Application -@cindex time -@cindex Time -@cindex socket -@cindex event -In the case of the UdpEchoServer, the call to @code{server->Start ()} gives -the @code{Application} the chance to schedule an event that will perform the -usual @emph{sockets} server sequence of socket creation, binding and -recvfrom (see Donahoo's UDPEchoServer.c). - -In the case of the UdpEchoClient, the call to @code{client->Start ()} gives -the @code{Application} the chance to schedule an event that will perform the -usual @emph{sockets} client sequence of socket creation, sendto and recvfrom -(see Donahoo's UDPEchoClient.c). - -@cindex event -Note that the start event for the server is scheduled to happen before the -start event of the client, just as you would start a server application before -you would attempt to start a client application in the real world. - -@cindex socket!sendto -The ns-3 equivalent of the call to @code{sendo} in the client will -schedule (immediately) the transmission of a UDP packet over the just created -socket. This will cause the packet to percolate down the protocol stack and -eventually into the channel. The channel will schedule a reception event in -the net device on the destination node. This event will eventually percolate -up into the server application. The server application will create a reply -packet and send it back down its stack and eventually back to the channel. -The channel will schedule a reception event back in the client and this will -cause the reply to be sent back up the protocol stack to the client -application. - -The calls to @code{Stop ()} for both applications cause the sockets to be -torn down and therefore the sending and receiving of packets will be stopped -irrespective of other application settings (such as max packets and interval -in the client). - -Finally, we need to run the simulation and when the simulation run is complete, -clean up any resources allocated during the run. This is done by the calling -the following static methods: - -@verbatim - Simulator::Run (); - Simulator::Destroy (); -@end verbatim - -We now have the makings of a complete ns-3 network simulation. The -source code for the script should look like the following: - -@verbatim - #include "ns3/log.h" - #include "ns3/ptr.h" - #include "ns3/internet-stack.h" - #include "ns3/csma-channel.h" - #include "ns3/mac48-address.h" - #include "ns3/csma-net-device.h" - #include "ns3/csma-topology.h" - #include "ns3/csma-topology.h" - #include "ns3/csma-ipv4-topology.h" - #include "ns3/udp-echo-client.h" - #include "ns3/udp-echo-server.h" - #include "ns3/simulator.h" - #include "ns3/nstime.h" - - NS_LOG_COMPONENT_DEFINE ("UdpEchoSimulation"); - - using namespace ns3; - - int - main (int argc, char *argv[]) - { - LogComponentEnable ("UdpEchoSimulation", LOG_LEVEL_INFO); - - NS_LOG_INFO ("UDP Echo Simulation"); - - Ptr n0 = CreateObject (); - Ptr n1 = CreateObject (); - Ptr n2 = CreateObject (); - Ptr n3 = CreateObject (); - - Ptr lan = - CsmaTopology::CreateCsmaChannel (DataRate (5000000), MilliSeconds (2)); - - uint32_t nd0 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n0, lan, - Mac48Address("08:00:2e:00:00:00")); - - uint32_t nd1 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n1, lan, - Mac48Address("08:00:2e:00:00:01")); - - uint32_t nd2 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n2, lan, - Mac48Address("08:00:2e:00:00:02")); - - uint32_t nd3 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n3, lan, - Mac48Address("08:00:2e:00:00:03")); - - CsmaIpv4Topology::AddIpv4Address (n0, nd0, Ipv4Address ("10.1.1.1"), - Ipv4Mask ("255.255.255.0")); - - CsmaIpv4Topology::AddIpv4Address (n1, nd1, Ipv4Address ("10.1.1.2"), - Ipv4Mask ("255.255.255.0")); - - CsmaIpv4Topology::AddIpv4Address (n2, nd2, Ipv4Address ("10.1.1.3"), - Ipv4Mask ("255.255.255.0")); - - CsmaIpv4Topology::AddIpv4Address (n3, nd3, Ipv4Address ("10.1.1.4"), - Ipv4Mask ("255.255.255.0")); - - uint32_t packetSize = 1024; - uint16_t port = 7; - uint32_t maxPacketCount = 1; - Time interPacketInterval = Seconds (1.); - - Ptr client = CreateObject (n0, "10.1.1.2", - port, maxPacketCount, interPacketInterval, packetSize); - - Ptr server = CreateObject (n1, port); - - server->Start(Seconds(1.)); - client->Start(Seconds(2.)); - - server->Stop (Seconds(10.)); - client->Stop (Seconds(10.)); - - Simulator::Run (); - Simulator::Destroy (); - } -@end verbatim - -@cindex tutorial-csma-echo.cc -Just to make sure you don't get caught up in debugging typographical errors -we have provided this source code for you (along with a copyright header) in -the @code{tutorial} subdirectory of the ns-3 distribution as -@code{tutorial-csma-echo.cc}. We used this opportunity to do some ``clean up'' -of some of our example cases by passing parameters using implicit conversion -sequences and removing some of the named parameters. [These were used for -pedagogic purposes and were not actually necessary.] - -@section Building the Script -@cindex Waf -C++ is a compiled language, so you know it had to happen. We have to build -the script before we run it. As mentioned before, we use the Waf build system -which is Python-based. We have to change gears slightly and switch ourselves -to Python mode in order to proceed. - -In each subdirectory of the ns-3 distribution in which there are -source files, you will find two files: one will be named @code{waf} and one -will be named @code{wscript}. The former, @code{waf}, is a link that allows -one to start the build process from any subdirectory. We can ignore that one. -The file we need to deal with is @code{wscript}. - -@cindex wscript -Open the file @code{ns-3-dev/tutorial/wscript} in your favorite editor -[remember I'm assuming that you have the distribution saved in a -repository under a directory called @code{repos} in you home directory.] - -@cindex Python -You should see the following Python code (after an emacs mode line). - -@verbatim - def build(bld): - obj = bld.create_ns3_program('hello-simulator') - obj.source = 'hello-simulator.cc' -@end verbatim - -These are the only instructions required to build a simulation (I told you -it wasn't going to be too bad). The line with the method -@code{bld.create_ns3_program} tells the build system to create an object -file that is a program (executable) named @code{hello-simulator}. The -following line, with the method @code{obj.source} tells the build system that -the source file for the program is the file @code{hello-simulator.cc'} in the -local directory. The required libraries are linked for you for free. - -All that needed to be done in order to build the new simulation using the new -source file was to copy the two lines describing the @code{hello-simulator} -program and change the names to @code{tutorial-csma-echo}. You can see these -lines in the @code{wscript} file, - -@verbatim - def build(bld): - obj = bld.create_ns3_program('hello-simulator') - obj.source = 'hello-simulator.cc' - - obj = bld.create_ns3_program('tutorial-csma-echo') - obj.source = 'tutorial-csma-echo.cc' - - ... -@end verbatim - -When you built the system above, you actually already built this new -simulation and a number of other examples. Since you have already configured -@code{Waf} and built the @code{tutorial-csma-echo} script, you can run the -simulation in the same way as you ran the @code{hello-simulator} script using -the @code{waf --run} command: - -@verbatim -~/repos/ns-3-dev/tutorial > waf --run tutorial-csma-echo -Entering directory `~/repos/ns-3-dev/build' -Compilation finished successfully -UDP Echo Simulation -~/repos/ns-3-dev/tutorial > -@end verbatim diff -r c9133c87760d -r 7ff69b244b5b doc/tutorial/in-process/log.texi --- a/doc/tutorial/in-process/log.texi Sun Jan 02 22:57:04 2011 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,24 +0,0 @@ -@node Logging -@chapter Logging -@anchor{chap:Logging} - -This chapter is the first in a series of chapters discussing things that -one can do to modify the input or output of existing ns-3 scripts. - -Examples: -@itemize @bullet -@item Enable or disable the generation of log messages, with fine granularity -@item Set default values for configuration values in the system -@item Generate a report of all configuration values used during a simulation -run (not yet implemented) -@item Set or get values of member variables on objects already instantiated -@item Customizing the tracing output of the script -@item Generate statistics on (not yet implemented) -@item Perform a large number of independent runs of the same simulation -@end itemize - -@node Logging Basics -@section Logging Basics - -@node Enabling Log Output -@section Enabling Log Output diff -r c9133c87760d -r 7ff69b244b5b doc/tutorial/in-process/other.texi --- a/doc/tutorial/in-process/other.texi Sun Jan 02 22:57:04 2011 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2189 +0,0 @@ -@c ======================================================================== -@c Other Network Topologies -@c ======================================================================== - -@node Other-network-topologies -@chapter Other Network Topologies -@cindex topology -@cindex Channel -@cindex NetDevice -@cindex topology!bus -@cindex topology!point-to-point -@cindex PointToPointChannel -@cindex PointToPointNetDevice - -@emph{Network topology} is the study of the arrangement of of the elements -(in @command{ns-3} represented by the classes @code{Channel} and @code{Node}) -of a network. Two fundamental types of physical topologies are the -@emph{point-to-point} and @emph{bus} topologies. We have already been exposed -to the @command{ns-3} channel specialization named @code{CsmaChannel}. This is -a simulation of a bus network. We also provide a simulation of a -point-to-point channel with associated net devices. As described previously, -the associated C++ classes specialize the @command{ns-3} base classes -@code{NetDevice} and @code{Channel} and are called @code{PointToPointNetDevice} -and @code{PointToPointChannel} respectively. - -We will use combinations of these bus and point-to-point topology elements -to show how to create several commonly seen network topologies. - -@section A Point-to-Point Network -We're going to take what might be seen as a step backward and look at a simple -point-to-point network. We will be building the simplest network you can -imagine. A serial link (point to point) between two computers. When you -see this point-to-point network, you can think of an RS-422 (or RS-232 for -you old-timers) cable. This topology is shown below. - -@sp 1 -@center @image{figures/pp,,,,png} - -@cindex CreateObject -@cindex InternetNode -We have provided a file for you in the @code{tutorial} -directory called @code{tutorial-point-to-point.cc}. You should now be -familiar enough with the system to pick out fairly easily what has been -changed. Let's focus on the following lines: - -@verbatim - Ptr n0 = CreateObject (); - Ptr n1 = CreateObject (); - - Ptr link = PointToPointTopology::AddPointToPointLink ( - n0, n1, DataRate (38400), MilliSeconds (20)); - - PointToPointTopology::AddIpv4Addresses (link, n0, "10.1.1.1", - n1, "10.1.1.2"); -@end verbatim - -You can see that we created two @code{InternetNode} objects in the usual way. -Then, instead of creating a @code{CsmaChannel} we create a -@code{PointToPointChannel}. This point-to-point channel, which we call -@code{link}, connects node zero (@code{n0}) and node one (@code{n1}) over a -simulated link that runs at 38400 bits per second and has a 20 millisecond -simulated speed-of-light delay. This call also creates appropriate net devices -and attaches them to nodes zero and one. - -We then add IP addresses to the net devices we just created using the topology -helper @code{AddIpv4Addresses}. Node zero gets the IP address 10.1.1.1 and -node one gets the IP address 10.1.1.2 assigned. - -The alert tutorial user may wonder what the network number or prefix is of -those IP addresses. The point-to-point topology assumes that you want a -@code{/30} subnet and assigns an appropriate net mask for you. It then then -@emph{asserts} that the network numbers of the two net devices match. So there -is an implicit network mask created down in the topology code that looks like, - -@verbatim - Ipv4Mask netmask("255.255.255.252"); -@end verbatim - -The rest of the code you should recognize and understand. We are just going -to echo one packet across the point-to-point link. You should be now be able -to build and run this example and to locate and interpret the ASCII trace -file. This is left as an exercise for you. - -The file @code{tutorial-point-to-point.cc} is reproduced here for your -convenience: - -@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/log.h" -#include "ns3/ptr.h" -#include "ns3/internet-stack.h" -#include "ns3/point-to-point-channel.h" -#include "ns3/mac48-address.h" -#include "ns3/point-to-point-net-device.h" -#include "ns3/point-to-point-topology.h" -#include "ns3/udp-echo-client.h" -#include "ns3/udp-echo-server.h" -#include "ns3/simulator.h" -#include "ns3/nstime.h" -#include "ns3/ascii-trace.h" -#include "ns3/pcap-trace.h" -#include "ns3/global-route-manager.h" - -NS_LOG_COMPONENT_DEFINE ("PointToPointSimulation"); - -using namespace ns3; - -// Network topology -// -// point to point -// +--------------+ -// | | -// n0 n1 -// -int -main (int argc, char *argv[]) -{ - LogComponentEnable ("PointToPointSimulation", LOG_LEVEL_INFO); - - NS_LOG_INFO ("Point to Point Topology Simulation"); - - Ptr n0 = CreateObject (); - Ptr n1 = CreateObject (); - - Ptr link = PointToPointTopology::AddPointToPointLink ( - n0, n1, DataRate (38400), MilliSeconds (20)); - - PointToPointTopology::AddIpv4Addresses (link, n0, "10.1.1.1", - n1, "10.1.1.2"); - - uint16_t port = 7; - - Ptr client = CreateObject (n0, "10.1.1.2", - port, 1, Seconds(1.), 1024); - - Ptr server = CreateObject (n1, port); - - server->Start(Seconds(1.)); - client->Start(Seconds(2.)); - - server->Stop (Seconds(10.)); - client->Stop (Seconds(10.)); - - AsciiTrace asciitrace ("tutorial.tr"); - asciitrace.TraceAllQueues (); - asciitrace.TraceAllNetDeviceRx (); - - Simulator::Run (); - Simulator::Destroy (); -} -@end verbatim - -@section A Star Network -A point-to-point network is considered a special case of a star network. As -you might expect, the process of constructing a star network is an extension -of the very simple process used for a point-to-point link. We have provided -a file for you in the @code{tutorial} directory called @code{tutorial-star.cc} -that implements a simple star network as seen below. - -@sp 1 -@center @image{figures/star,,,,png} - -In order to create a star network, we need to be able to instantiate some -number (greater than one) of net devices on a node. In the name of simplicity -of use, the @code{PointToPointTopology} topology helper does not allow one to -do this. We provided a separate topology helper class, the -@code{PointToPointIpv4Topology} helper class that provides the slightly finer -granularity we need to accomplish a star network. In order to use this new -helper we have to load the definitions by including the appropriate file. - -@verbatim - #include "ns3/point-to-point-ipv4-topology.h" -@end verbatim - -The star that we're going to create has a node in the center (@code{n0}) with -six nodes surrounding (@code{n1} - @code{n6}). You should be able to easily -find and understand the code that creates these nodes. - -@verbatim - Ptr n0 = CreateObject (); - Ptr n1 = CreateObject (); - Ptr n2 = CreateObject (); - Ptr n3 = CreateObject (); - Ptr n4 = CreateObject (); - Ptr n5 = CreateObject (); - Ptr n6 = CreateObject (); -@end verbatim - -Next, we get into the differences between the @code{PointToPointTopology} -helper and the @code{PointToPointIpv4Topology} helper. The -@code{PointToPointIpv4Topology} helper looks and feels a little like the -@code{CsmaIpv4Topology} helper. Just like you created a CSMA channel -previously, you need to create a point-to-point channel. The following -code creates a @code{PointToPointChannel} and calls it @code{link01}. You can -interpret this name as being the channel (or @emph{link}) from node zero to -node one. - -@verbatim - Ptr link01 = - PointToPointIpv4Topology::CreateChannel (DataRate (38400), - MilliSeconds (20)); -@end verbatim - -You need to provide a data rate for the channel which we set at 38400 bits -per second. You must also provide a speed-of-light delay which we set at -20 milliseconds. - -Just as you added a net device to the nodes in the CSMA tutorial section, you -do the same here but with a point-to-point net device. The following code -illustrates how we do that: - -@verbatim - uint32_t nd01 = PointToPointIpv4Topology::AddNetDevice (n0, - link01); -@end verbatim - -We call the @code{PointToPointIpv4Topology} helper and ask it to add a net -device to node zero (@code{n0}) and connect it to the appropriate -point-to-point link (@code{link01}) which you will recall is the serial link -from node zero to node one. - -If you look at the following code, you will see the same calls are repeated -to create the remaining five point-to-point channels and connect them -to net devices on node zero. - -The next new code is found after the ``spokes'' of the star have been created. -It looks like the following: - -@verbatim - uint32_t nd1 = PointToPointIpv4Topology::AddNetDevice (n1, link01); - uint32_t nd2 = PointToPointIpv4Topology::AddNetDevice (n2, link02); - uint32_t nd3 = PointToPointIpv4Topology::AddNetDevice (n3, link03); - uint32_t nd4 = PointToPointIpv4Topology::AddNetDevice (n4, link04); - uint32_t nd5 = PointToPointIpv4Topology::AddNetDevice (n5, link05); - uint32_t nd6 = PointToPointIpv4Topology::AddNetDevice (n6, link06); -@end verbatim - -Here we are creating the net devices on the nodes surrounding the center node. -In the first call, we are adding a net device on node one (@code{n1}) and -connecting that net device to the channel named @code{link01}. Remember that -we created the channel @code{link01} as the channel connecting node zero and -node one. We previously created a net device on node zero and attached that -device to @code{link01}. Here we are connecting the other side of that link -to node one. The return value from this call is the net device index of the -created net device. - -The next section of code adds addresses to the net devices we just created. -The first call adds the IP address 10.1.1.1 to the net device going from -node zero to node one. Recall that we first created a node named @code{n0} -and a channel called @code{link01}. We added a net device to @code{n0} and -remembered the net device index as the @code{uint32_t nd01}. This meant -the net device @emph{nd} on node @emph{0} that we connected to node @emph{1}. -We call @code{AddAddress} to add an IP address (10.1.1.1) to the net device -on node zero identified by the net device index @code{nd01}. We provide a -net mask suitable for a point to point network. This is typically a /30 -address but we don't force that in this API. - -After setting up the address on node zero, we do the same for the node on -the other end of the ``spoke'' --- in this case node one, with its single -net device. Note that the network number is the same on both sides of this -network. - -@verbatim - PointToPointIpv4Topology::AddAddress (n0, nd01, "10.1.1.1", - ``255.255.255.252''); - - PointToPointIpv4Topology::AddAddress (n1, nd1, "10.1.1.2", - ``255.255.255.252''); -@end verbatim - -The following code repeats this pattern assining similar IP addresses to the -remaining net devices. Note that there are no @code{Mac48Address} address -assignments --- they are not required. - -The rest of the code you should recognize and understand. We are just going -to echo one packet across the point-to-point link. You should be now be able -to build and run this example and to locate and interpret the ASCII trace -file. This is left as an exercise for you. - -The file @code{tutorial-star.cc} is reproduced here for your convenience: - -@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/log.h" -#include "ns3/ptr.h" -#include "ns3/internet-stack.h" -#include "ns3/point-to-point-channel.h" -#include "ns3/mac48-address.h" -#include "ns3/point-to-point-net-device.h" -#include "ns3/point-to-point-ipv4-topology.h" -#include "ns3/udp-echo-client.h" -#include "ns3/udp-echo-server.h" -#include "ns3/simulator.h" -#include "ns3/nstime.h" -#include "ns3/ascii-trace.h" -#include "ns3/pcap-trace.h" -#include "ns3/global-route-manager.h" - -NS_LOG_COMPONENT_DEFINE ("StarSimulation"); - -using namespace ns3; - -// Network topology -// -// n3 n2 -// | / -// | / -// n4 --- n0 --- n1 -// / | -// / | -// n5 n6 - -int -main (int argc, char *argv[]) -{ - LogComponentEnable ("StarSimulation", LOG_LEVEL_INFO); - - NS_LOG_INFO ("Star Topology Simulation"); - - Ptr n0 = CreateObject (); - Ptr n1 = CreateObject (); - Ptr n2 = CreateObject (); - Ptr n3 = CreateObject (); - Ptr n4 = CreateObject (); - Ptr n5 = CreateObject (); - Ptr n6 = CreateObject (); - - Ptr link01 = - PointToPointIpv4Topology::CreateChannel (DataRate (38400), - MilliSeconds (20)); - - uint32_t nd01 = PointToPointIpv4Topology::AddNetDevice (n0, - link01); - - Ptr link02 = - PointToPointIpv4Topology::CreateChannel (DataRate (38400), - MilliSeconds (20)); - - uint32_t nd02 = PointToPointIpv4Topology::AddNetDevice (n0, - link02); - - Ptr link03 = - PointToPointIpv4Topology::CreateChannel (DataRate (38400), - MilliSeconds (20)); - - uint32_t nd03 = PointToPointIpv4Topology::AddNetDevice (n0, - link03); - - Ptr link04 = - PointToPointIpv4Topology::CreateChannel (DataRate (38400), - MilliSeconds (20)); - - uint32_t nd04 = PointToPointIpv4Topology::AddNetDevice (n0, - link04); - - Ptr link05 = - PointToPointIpv4Topology::CreateChannel (DataRate (38400), - MilliSeconds (20)); - - uint32_t nd05 = PointToPointIpv4Topology::AddNetDevice (n0, - link05); - - Ptr link06 = - PointToPointIpv4Topology::CreateChannel (DataRate (38400), - MilliSeconds (20)); - - uint32_t nd06 = PointToPointIpv4Topology::AddNetDevice (n0, link06); - - uint32_t nd1 = PointToPointIpv4Topology::AddNetDevice (n1, link01); - uint32_t nd2 = PointToPointIpv4Topology::AddNetDevice (n2, link02); - uint32_t nd3 = PointToPointIpv4Topology::AddNetDevice (n3, link03); - uint32_t nd4 = PointToPointIpv4Topology::AddNetDevice (n4, link04); - uint32_t nd5 = PointToPointIpv4Topology::AddNetDevice (n5, link05); - uint32_t nd6 = PointToPointIpv4Topology::AddNetDevice (n6, link06); - - PointToPointIpv4Topology::AddAddress (n0, nd01, "10.1.1.1", - "255.255.255.252"); - - PointToPointIpv4Topology::AddAddress (n1, nd1, "10.1.1.2", - "255.255.255.252"); - - PointToPointIpv4Topology::AddAddress (n0, nd02, "10.1.2.1", - "255.255.255.252"); - - PointToPointIpv4Topology::AddAddress (n2, nd2, "10.1.2.2", - "255.255.255.252"); - - PointToPointIpv4Topology::AddAddress (n0, nd03, "10.1.3.1", - "255.255.255.252"); - - PointToPointIpv4Topology::AddAddress (n3, nd3, "10.1.2.2", - "255.255.255.252"); - - PointToPointIpv4Topology::AddAddress (n0, nd04, "10.1.4.1", - "255.255.255.252"); - - PointToPointIpv4Topology::AddAddress (n4, nd4, "10.1.4.2", - "255.255.255.252"); - - PointToPointIpv4Topology::AddAddress (n0, nd05, "10.1.5.1", - "255.255.255.252"); - - PointToPointIpv4Topology::AddAddress (n5, nd5, "10.1.5.2", - "255.255.255.252"); - - PointToPointIpv4Topology::AddAddress (n0, nd06, "10.1.6.1", - "255.255.255.252"); - - PointToPointIpv4Topology::AddAddress (n6, nd6, "10.1.6.2", - "255.255.255.252"); - - uint16_t port = 7; - - Ptr client = CreateObject (n0, "10.1.1.2", - port, 1, Seconds(1.), 1024); - - Ptr server = CreateObject (n1, port); - - server->Start(Seconds(1.)); - client->Start(Seconds(2.)); - - server->Stop (Seconds(10.)); - client->Stop (Seconds(10.)); - - AsciiTrace asciitrace ("tutorial.tr"); - asciitrace.TraceAllQueues (); - asciitrace.TraceAllNetDeviceRx (); - - Simulator::Run (); - Simulator::Destroy (); -} -@end verbatim - -@subsection Routing -If you are really excited about this simulator you may have already tried to -modify the scripts outside the tutorial. I know that one of the first things -that would have occurred to me when I saw the star network would have been to -start trying to add applications to echo packets from nodes other than zero. -If you tried, for example, to start the echo client on node one instead of -node zero, you would have found an empty trace file. The reason for this -is that you have now created an internetwork. This means you will need to -enable internetwork routing. - -We have provided a file for you in the @code{tutorial} directory called -@code{tutorial-star-routing.cc} to show you how this is done. This extremely -tricky and difficult change is shown below: - -@verbatim - GlobalRouteManager::PopulateRoutingTables (); -@end verbatim - -This one-line addition, located just before the simulation runs, tells the -@command{ns-3} @emph{global route manager} to walk the topology you created and -build internetwork routing tables for all of the nodes in the simulation. -We changed the client application so that it runs on node four: - -@verbatim - Ptr client = CreateObject (n4, "10.1.1.2", - port, 1, Seconds(1.), 1024); -@end verbatim - -Now if you build and run @code{tutorial-star-routing.cc} you can examine the -@code{tutorial.tr} file and see that your UDP echo packets are now correctly -routed through the topology. - -@section A Dumbbell Network -One of the most interesting simple topologies (from a phenomenological point of -view) is commonly called a dumbbell network. The name derives from a -superficial similarity in form to a piece of exercise equipment. - -The dumbbell model is typically composed of two bus or star network elements -connected via a point-to-point link. The point-to-point link is usually -configured with a lower bandwidth than the bus elements to provide a -@emph{choke point}. - -The following is a representation of the topology. - -@sp 1 -@center @image{figures/dumbbell,,,,png} - -We have provided a file that constructs this dumbbell network and creates -enough data flowing across the choke point that some packets will be dropped. -The file is called @code{tutorial-linear-dumbbell.cc} and is located in the -@code{tutorial} directory. We have already covered all of the code used to -create this network, so we will just quickly go over the main sections of the -script. - -The first section creates a CSMA lan that will become the left side of the -dumbbell network. This code should be very familiar since we used the same -process to create our first example. - -@verbatim -// -// Create the lan on the left side of the dumbbell. -// - Ptr n0 = CreateObject (); - Ptr n1 = CreateObject (); - Ptr n2 = CreateObject (); - Ptr n3 = CreateObject (); - - Ptr lan1 = - CsmaTopology::CreateCsmaChannel (DataRate (10000000), MilliSeconds (2)); - - uint32_t nd0 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n0, lan1, - "08:00:2e:00:00:00"); - - uint32_t nd1 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n1, lan1, - "08:00:2e:00:00:01"); - - uint32_t nd2 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n2, lan1, - "08:00:2e:00:00:02"); - - uint32_t nd3 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n3, lan1, - "08:00:2e:00:00:03"); - - CsmaIpv4Topology::AddIpv4Address (n0, nd0, "10.1.1.1", "255.255.255.0"); - CsmaIpv4Topology::AddIpv4Address (n1, nd1, "10.1.1.2", "255.255.255.0"); - CsmaIpv4Topology::AddIpv4Address (n2, nd2, "10.1.1.3", "255.255.255.0"); - CsmaIpv4Topology::AddIpv4Address (n3, nd3, "10.1.1.4", "255.255.255.0"); -@end verbatim - -The code to generate the CSMA lan on the right side is similar; only the names -have been changed. - -@verbatim -// -// Create the lan on the right side of the dumbbell. -// - Ptr n4 = CreateObject (); - Ptr n5 = CreateObject (); - Ptr n6 = CreateObject (); - Ptr n7 = CreateObject (); - - Ptr lan2 = - CsmaTopology::CreateCsmaChannel (DataRate (10000000), MilliSeconds (2)); - - uint32_t nd4 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n4, lan2, - "08:00:2e:00:00:04"); - - uint32_t nd5 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n5, lan2, - "08:00:2e:00:00:05"); - - uint32_t nd6 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n6, lan2, - "08:00:2e:00:00:06"); - - uint32_t nd7 = CsmaIpv4Topology::AddIpv4CsmaNetDevice (n7, lan2, - "08:00:2e:00:00:07"); - - CsmaIpv4Topology::AddIpv4Address (n4, nd4, "10.1.2.1", "255.255.255.0"); - CsmaIpv4Topology::AddIpv4Address (n5, nd5, "10.1.2.2", "255.255.255.0"); - CsmaIpv4Topology::AddIpv4Address (n6, nd6, "10.1.2.3", "255.255.255.0"); - CsmaIpv4Topology::AddIpv4Address (n7, nd7, "10.1.2.4", "255.255.255.0"); -@end verbatim - -Next, we create a point to point link to connect the two lans. We connect -the point-to-point channel between nodes three (on the left lan) and four -(on the right lan). You should recognize this as substantially similar to -the link setup from the @code{point-to-point} example. - -@verbatim -// -// Create the point-to-point link to connect the two lans. -// - Ptr link = PointToPointTopology::AddPointToPointLink ( - n3, n4, DataRate (38400), MilliSeconds (20)); - - PointToPointTopology::AddIpv4Addresses (link, n3, "10.1.3.1", - n4, "10.1.3.2"); -@end verbatim - -Then we configure data flows. We create four echo clients that send UDP -packets from the left side lan to servers created on the right side lan. -Notice that we send 100 packets with an inter-packet gap of ten milliseconds -instead of the single packet we have previously used. This data rate is -sufficient to saturate the point-to-point link and will cause packets to be -dropped when the queue on the link net devices overflows (the default maximum -queue depth is 100 packets). Note that we stagger the start of the echo -clients to slowly bring up the data rates. - -@verbatim -// -// Create data flows across the link: -// n0 ==> n4 ==> n0 -// n1 ==> n5 ==> n1 -// n2 ==> n6 ==> n2 -// n3 ==> n7 ==> n3 -// - uint16_t port = 7; - - Ptr client0 = CreateObject (n0, "10.1.2.1", - port, 100, Seconds(.01), 1024); - Ptr client1 = CreateObject (n1, "10.1.2.2", - port, 100, Seconds(.01), 1024); - Ptr client2 = CreateObject (n2, "10.1.2.3", - port, 100, Seconds(.01), 1024); - Ptr client3 = CreateObject (n3, "10.1.2.4", - port, 100, Seconds(.01), 1024); - - Ptr server4 = CreateObject (n4, port); - Ptr server5 = CreateObject (n5, port); - Ptr server6 = CreateObject (n6, port); - Ptr server7 = CreateObject (n7, port); - - server4->Start(Seconds(1.)); - server5->Start(Seconds(1.)); - server6->Start(Seconds(1.)); - server7->Start(Seconds(1.)); - - client0->Start(Seconds(2.)); - client1->Start(Seconds(2.1)); - client2->Start(Seconds(2.2)); - client3->Start(Seconds(2.3)); - - server4->Stop (Seconds(10.)); - server5->Stop (Seconds(10.)); - server6->Stop (Seconds(10.)); - server7->Stop (Seconds(10.)); - - client0->Stop (Seconds(10.)); - client1->Stop (Seconds(10.)); - client2->Stop (Seconds(10.)); - client3->Stop (Seconds(10.)); -@end verbatim - -The remainder of the file should be quite familiar to you. Go ahead and -run @code{tutorial-linear-dumbbell}. Now take a look at the trace -(@code{tutorial.tr}) file. You will now see trace lines that begin with -@code{d}. Alternatively you can search for the string ``queue-drop'' which -is the expansion of the drop code ('d'). - -Interpretation of a dropped packet is straightforward. We have expanded -the first @code{queue-drop} trace for you below. See the section on ASCII -tracing for details. - -@verbatim - 00 d - 01 2.40938 - 02 nodeid=3 - 03 device=1 - 04 queue-drop - 05 pkt-uid=124 - 06 LLCSNAP(type 0x800) - 07 IPV4( - 08 tos 0x0 - 09 ttl 63 - 10 id 20 - 11 offset 0 - 12 flags [none] - 13 length: 1052) 10.1.1.3 > 10.1.2.3 - 14 UDP(length: 1032) - 15 49153 > 7 - 16 DATA (length 1024) -@end verbatim - -We leave it as an exercise to examine the trace files in more detail. - -@c ======================================================================== -@c Nonlinear Thinking -@c ======================================================================== - -@node Nonlinear-Thinking -@chapter Nonlinear Thinking - -One thing that all of our examples so far have in common is that they are -composed of a linear collection of calls into the @command{ns-3} system. The -programmers among the readers may have wondered why there is not as much -as a for-loop in all of the examples. The answer is that we wanted to -introduce you to @command{ns-3} scripting with a minimum of conceptual -overhead. We're going to remedy that situation shortly. - -We have written a number of @command{ns-3} scripts in C++. Although we have -been perfectly linear in our script implementations, just like any other C++ -program, an @command{ns-3} script can use any features of the language you -desire. If you will look back at the @code{tutorial-linear-dumbbell.cc} -example, you may notice that the code to create the left and right sides of -the dumbbell is operationally identical --- only the names change. An obvious -improvement of this program would be to use subroutines to create the sides. -Since we are working with C++, we should probably do this in an -object-oriented way. Since object-oriented design is somewhat of a black art -to some people, we'll take some time here and outline a simple methodology -you can follow. - -@section Object Design 101 --- Class Ipv4BusNetwork -If you are a master of object oriented design, feel free to skip or skim this -section, in which we derive a simplistic but fully operational bus network -class. - -So you want to create a BusNetwork class. Often the biggest hurdle in a -design is figuring out how to get started. One of the simplest and most -straightforward ways to do an object decomposition of a problem is to simply -write down a description of the problem and take a look at the words -you used. Let's take some time and do that, first at a very high level. - -@example -A bus network is an implementation of a particular network topology that -contains some number of nodes. Each of these nodes is attached to a single -multi-drop channel. The network itself has some attributes independent of -the topology such as a network mask, network number (prefix) and base IP -address. -@end example - -The first thing to do is to focus on the nouns and adjectives. These will -give you a starting point for required classes and member variables. - -Immediately we can notice that at the highest level we are talking about the -noun @emph{network}. This probably won't surprise you. We also have an -adjective that modifies the noun --- @emph{bus}. This should lead us to our -first class definition. Usually class names are constructed in the same way -as an English language sentence would be spoken. For example, one would speak -of a @emph{bus network} in conversation, so we would normally create a -@code{class BusNetwork} to represent it. - -One thing to note is that we have used two words in our description quite -naturally: @emph{is} and @emph{has}. When you see these words should should -immediately think of the object-oriented concepts of @emph{ISA} (inheritance) -and @emph{HASA} (containment) respectively. We wrote that a bus network -@emph{is} an implementation of a particular network topology. Perhaps you -will agree that there is a natural base class called @code{Network} that -@emph{has} the attributes discussed above. The fact that a @code{BusNetwork} -@emph{ISA} kind of @code{Network} suggests inheritance. Let's capture that -thought right away remembering that we're focused on IP version four here: - -@verbatim - class Ipv4Network - { - public: - Ipv4Address m_network; - Ipv4Mask m_mask; - Ipv4Address m_baseAddress; - }; - - class Ipv4BusNetwork : public Ipv4Network - { - }; -@end verbatim - -Let's take a look at the @emph{HASA} relationships of the bus network. Clearly -it will @emph{have} a reference to the underlying channel that implements the -actual communications medium. We use smart pointers for those references, so -one member variable is obvious: - -@verbatim - Ptr m_channel; -@end verbatim - -A bus network will also need to contain references to all of the nodes we -eventually want to create. If you are working in C++ and see the words contain -or container, you should immediately think of the Standard Template Library -or STL. A quick search of the available containers there will probably lead -you to consider the vector class. A vector is a container that looks like an -array. This is just what we need here. Again, we want to use smart pointers -to reference our nodes, so the declaration of the vector would look like, - -@verbatim - std::vector > m_nodes; -@end verbatim - -It will save you headaches in the future if you notice that the space between -the two right brackets is required to differentiate this situation from a -right-shift operator. So we have a pretty good start already after just a -little work. Now we need to turn our attention to actions. Let's write -another little description of the things you consider doing to a Bus network. - -@example -We need to be able to create a bus network. We need to be able to delete a -bus network. We need to be able to get a handle to a node in order to add -applications. We need to be able to set the network, mask and base address -somehow, specify how many nodes to create and provide the underlying channel -its required bandwidth and delay parameters. -@end example - -We now look at the @emph{verbs} in that sentence. These will give a good -starting point for the methods of the classes. For example, the verbs -@emph{create} and @emph{delete} should suggest @emph{constructor} and -@emph{destructor}. The verb @emph{get} leads us to providing a method called -@code{GetNode}. We have to provide a number of parameters so we can either -provide @emph{setters} or we can simply pass them in as parameters to our -constructors. Since this is a simple example, we won't bother to implement -getters and setters (methods to get and set member variables to enhance data -hiding). Let's use this guidance to finish up our class declarations: - -@verbatim - class Ipv4Network - { - public: - Ipv4Network (Ipv4Address network, Ipv4Mask mask, Ipv4Address address); - virtual ~Ipv4Network (); - - Ipv4Address m_network; - Ipv4Mask m_mask; - Ipv4Address m_baseAddress; - }; - - class Ipv4BusNetwork : public Ipv4Network - { - public: - Ipv4BusNetwork ( - Ipv4Address network, - Ipv4Mask mask, - Ipv4Address startAddress, - DataRate bps, - Time delay, - uint32_t n); - - virtual ~Ipv4BusNetwork (); - - Ptr GetNode (uint32_t n); - - private: - std::vector > m_nodes; - Ptr m_channel; - }; -@end verbatim - -That's it. We have actually already walked through almost all of the code -required to construct a bus network in our @code{tutorial-csma-echo.cc} -example, so let's just jump forward and take a look at an implementation -of this thing. We provide an implementation for you in the files -@code{ipv4-bus-network.h} and @code{ipv4-bus-network.cc} located in the -@code{tutorial} directory. We also provide an example that uses the new -class in the file @code{tutorial-bus-network.cc}. - -The interesting method from our current perspective is the Ipv4BusNetwork -constructor, shown below: - -@verbatim - Ipv4BusNetwork::Ipv4BusNetwork ( - Ipv4Address network, - Ipv4Mask mask, - Ipv4Address baseAddress, - DataRate bps, - Time delay, - uint32_t n) - : - Ipv4Network (network, mask, baseAddress) - { - Ipv4AddressGenerator::SeedNetwork (mask, network); - Ipv4AddressGenerator::SeedAddress (mask, baseAddress); - - m_channel = CsmaTopology::CreateCsmaChannel (bps, delay); - - for (uint32_t i = 0; i < n; ++i) - { - Ptr node = CreateObject (); - uint32_t nd = CsmaIpv4Topology::AddIpv4CsmaNetDevice (node, m_channel, - Mac48Address::Allocate ()); - Ipv4Address address = Ipv4AddressGenerator::AllocateAddress (mask, - network); - CsmaIpv4Topology::AddIpv4Address (node, nd, address, mask); - m_nodes.push_back (node); - } - } -@end verbatim - -Notice that we do the simple and straightforward thing and pass all of our -parameters to the constructor. For those unfamiliar with C++, the line after -the colon and before the opening brace (shown below), - -@verbatim - : - Ipv4Network (network, mask, baseAddress) - { -@end verbatim - -Passes the appropriate parameters to the constructor of the base class -@code{Ipv4Network}. There are two new calls that we haven't seen immediately -after this initialization. They are: - -@verbatim - Ipv4AddressGenerator::SeedNetwork (mask, network); - Ipv4AddressGenerator::SeedAddress (mask, baseAddress); -@end verbatim - -We provide an IP address generator class to allow us to programmatically -allocate IP addresses. The first call to @code{SeedNetwork} gives the -address generator a starting network number to use when generating addresses. -The second call to @code{SeedAddress} gives the address generator a starting -IP address to use. There is a starting network and starting address for each -of the 32 possible network masks. Later in the for loop, you will see a -call to @code{AllocateAddress} in which the IP address for each node created -in the loop is actually generated. - -The only unfamiliar call in the reset of the constructor will be: - -@verbatim - m_nodes.push_back (node); -@end verbatim - -This is the STL code to add the newly created node to the vector of nodes -attached to the bus. - -For your convenience, we reproduce the entire bus network implementation below: - -@verbatim - /* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ - /* - * Copyright (c) 2007 University of Washington - * - * 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/mac48-address.h" - #include "ns3/csma-net-device.h" - #include "ns3/csma-topology.h" - #include "ns3/csma-ipv4-topology.h" - - #include "ipv4-bus-network.h" - #include "ipv4-address-generator.h" - - namespace ns3 { - - Ipv4Network::Ipv4Network ( - Ipv4Address network, - Ipv4Mask mask, - Ipv4Address address) - : - m_network (network), m_mask (mask), m_baseAddress (address) - { - } - - Ipv4Network::~Ipv4Network () - { - } - - Ipv4BusNetwork::Ipv4BusNetwork ( - Ipv4Address network, - Ipv4Mask mask, - Ipv4Address baseAddress, - DataRate bps, - Time delay, - uint32_t n) - : - Ipv4Network (network, mask, baseAddress) - { - Ipv4AddressGenerator::SeedNetwork (mask, network); - Ipv4AddressGenerator::SeedAddress (mask, baseAddress); - - m_channel = CsmaTopology::CreateCsmaChannel (bps, delay); - - for (uint32_t i = 0; i < n; ++i) - { - Ptr node = CreateObject (); - uint32_t nd = CsmaIpv4Topology::AddIpv4CsmaNetDevice (node, m_channel, - Mac48Address::Allocate ()); - Ipv4Address address = Ipv4AddressGenerator::AllocateAddress (mask, - network); - CsmaIpv4Topology::AddIpv4Address (node, nd, address, mask); - m_nodes.push_back (node); - } - } - - Ipv4BusNetwork::~Ipv4BusNetwork () - { - } - - Ptr - Ipv4BusNetwork::GetNode (uint32_t n) - { - return m_nodes[n]; - } - - }; // namespace ns3 -@end verbatim - -@section Using Ipv4BusNetwork -If all you ever want to do with a bus network can be captured in a topology -with four nodes on the bus, the preceeding section may seem like a colossal -waste of time. This is probably not the case, though. Now that we have a -relatively abstract bus class, we can create bus networks with 4, 40 or 4000 -nodes with no additional effort. - -A use of the bus network class is shown in the file -@code{bus-network.cc} located in the @code{tutorial} directory. The -interesting code is, - -@verbatim - Ipv4BusNetwork bus ("10.1.0.0", "255.255.0.0", "0.0.0.3", - DataRate(10000000), MilliSeconds(20), 10); -@end verbatim - -Here we create a bus network with the network number ``10.1.0.0'' and the -network mask ``255.255.0.0'' that completes the IP network definition. You -can consider these together as ``10.1.0.0/16'' if you prefer. The next -parameter tells the bus to start numbering IP addresses of contained nodes at -``10.1.0.3'' (remember the network number will be combined). We provided a -data rate of 10 megabits per second and a latency of 20 milliseconds. -Finally, we ask the @code{Ipv4BusNetwork} object to create ten nodes in the -network. - -If you are feeling brave, go ahead and change the number of nodes to be 100, -1000, 10,000 or more to generate larger and larger networks. Before you go -too far, remember that a trace file will be generated when you run your -resulting program and ee asked the trace facility to trace all net device -receive events. This will include the reception of the broadcast ARP request -by all of the nodes in the simulation, so this can add up quickly. - -@c ======================================================================== -@c Summary -@c ======================================================================== - -@node Summary -@chapter Summary - -This concludes the first part of the tutorial. We have focused on -using the @command{ns-3} system to construct various network topologies and to -simulate sendng data across the networks; and we've shown you how to use the -trace facility to get access to simulation results. - -We now encourage you to play with the system a little. Experiment with what -we have provided. Build a hierarchical network simulation. Perhaps exercise -your object design skills and create a new @code{Ipv4DumbbellNetwork} class -to create dumbbell networks using the Ipv4BusNetwork class we just created. -Hint: An Ipv4DumbbellNetwork @emph{has} two @code{Ipv4BusNetwork} objects; -a left side and a right side. - -In the next part of the tutorial we are going to drop down a level and begin -examining the lower levels of the system in more detail. We are going to -explain how to change the behavior of the system and eventually how to write -new models and applications. This is a good time to make sure that you -thoroughly understand what we've gone over so far. - -@c ======================================================================== -@c Object Model -@c ======================================================================== - -@node Object-Model -@chapter Object Model - -@cindex Object Model -There are two distinctly different meanings associated with the term Object -Model. The first speaks to the implementation of an object system --- a system -view; and the second speaks to the application programming interface (classes -or objects) one uses to access some service or system --- an application view. - -As an example of the system view sense of the term, the C++ language has an -associated object model that describes how objects are laid out in memory, -how virtual functions work, how inheritance is implemented, constructor and -destructor execution ordering, template instantiation, etc. - -@cindex API -@cindex DOM -@cindex Document Object Model -In the case of the application view, the Document Object Model is a good -example. In the words of W3C, the Document Object Model (DOM) is an -application programming interface (API) for HTML and XML documents. It defines -the logical structure of documents and the way a document is accessed and -manipulated. - -@cindex API -@cindex COM -@cindex Component Object Model -The Component Object Model (COM) from Microsoft actually spans both meanings -of the term and extends further into policy statements. From a system -perspective, COM specifies an interface definition language, the layout of -objects virtual function tables, the formats of Globally Unique Identifiers -and also specifies lifetime management mechanisms for objects via reference -counting. From the point of view of the API, COM specifies a number of -Interfaces as well as functions such as CoCreateInstance and various -threading models. The COM specification extends to policy by disallowing -implementation inheritance. - -@cindex Feynman -The @command{ns-3} object model takes the C++ language (system level) object -model as its basis, and extends that model by providing an API for software -componentry. You may find terms like Component, Interface and QueryInterface -in the following discussion, or used informally in other discussions about -@command{ns-3}. It is important to understand from the outset that this is -the @command{ns-3} object model, and not any other object model. -Richard Feynman (an American physicist) once described the behavior of matter -and light on a very small scale in the following way, - -@quotation -``They do not behave like waves, they do not behave like particles, they do -not behave like clouds, or billiard balls, or weights on springs, or like -anything that you have ever seen.'' -@end quotation - -Just as students of quantum mechanics must rid themselves of preconceptions -regarding the behavior of matter at small scales, you should rid yourself of -any preconceptions you may have about components, interfaces and APIs for -software componentry before continuing. To paraphrase Feynman, @command{ns-3} -components do not behave like COM Components, or Java Beans, or CORBA -objects, or clouds or weights on springs, or like anything that you have -ever seen --- they are @command{ns-3} components. - -@section The C++ Object Model is the Root of all Things -@command{Ns-3} is primarily a C++ system. The system is written in C++ and -one can use standard C++ mechanisms for creating and using ns-3 objects. We -do not change this at all, nor do we make any pronouncements about the -superiority of one mechanism or another. What we will do is provide -convenience functions that we think will make creating and managing simulation -objects easier. - -@cindex CreateObject -Previously, you have seen objects created using the template function -@code{CreateObject} as in the following example: - -@verbatim - Ptr n0 = CreateObject (); -@end verbatim - -This line of code, while it may be unfamiliar to some, is pure C++. If you -were to look in the header file ptr.h, you would find the following definition -of the @code{CreateObject} template. - -@verbatim - template - Ptr CreateObject (void) - { - Ptr p = Ptr (new T (), false); - p->SetTypeId (T::GetTypeId ()); - return p; - } -@end verbatim - -@cindex template -As you can see, this template creates objects of type @code{T} using the -operator @code{new}. Its a little harder to find the corresponding delete --- -it's in the file @code{object.cc} inside the method @code{Object::MaybeDelete}, -but when that @code{Ptr} which you see above goes out of scope it will call -@code{Unref} and ultimately the C++ @code{delete} operator will be called. - -@cindex new -@cindex delete -The ns-3 system uses the C++ @code{new} and @code{delete} operators, so there -is really no reason that you as a user of the ns-3 system are forbidden from -using these or any other C++ mechanism. If you so desire, you can take on -the responsibility for managing object lifetime (i.e., do not use the -@code{Ptr} smart pointer), work directly with the @code{new} and @code{delete} -operators and call methods like any C++ object as in the following example: - -@verbatim - MyClass *obj = new MyClass (); - obj->Method(); - delete obj; -@end verbatim - -@cindex model -You, as a competent model author, are encouraged to use whatever methods you -think are appropriate in your private code. Remember, however, that the -public ns-3 APIs do use smart pointers to pass objects around in an effort to -reduce the burden of object lifetime management. If you do intend to export -an API publicly, you should use the same object lifetime management approaches -as those found in the ns-3 public API if only for consistency. - -These APIs are there for convenience and consistency, but do not change the -fact that in ns-3 all of the objects are really just C++ objects, ultimately -created using the C++ new operator with C++ constructor semantics and are -ultimately deleted using the C++ delete operator, following C++ destructor -semantics. Although it may sometimes appear so, there is really no system- -level magic going on in ns-3. Ns-3 components and interfaces are C++ objects -just like any other object and our object model is simply a collection of APIs -built on the normal C++ object model. - -@cindex Interface -@cindex Abstract Data Type -@cindex ADT -@cindex Abstract Base Class -@cindex ABC -@section Interface -There are many different ideas floating around of what exactly the term -@emph{interface} means. Originally an interface just meant a communication -boundary between two entities. As the concepts of object oriented programming -(OOP) were surfacing in the 1980s, the term interface was applied to the -collection of access methods for the modular entities that were being defined. - -@cindex OOP -@cindex Object Oriented Programming -Two distinct approaches developed regarding specifying access mechanisms for -objects. The OOP purists were very concerned about object reuse and were led -to Abstract Data Types (ADT). These were eventually implemented in the case -of C++, as pure virtual methods in Abstract Base Classes (ABC). Another group -of folks was more interested in simply specifying object access methods in one -place and using inheritance as the primary reuse mechanism. - -Bjarne Stroustroup, the creator of C++, embraced both approaches. He makes -the following interesting observation: - -@quotation -``Many classes [@dots{}] are useful both as themselves and also as bases for -derived classes. [@dots{}] Some classes, such as class @strong{Shape}, -represent abstract concepts for which objects cannot exist.'' -@end quotation - -@cindex PIMPL -@command{Ns-3} does not pick and enforce a particular approach. In -@command{ns-3} an interface is determined completely by a class declaration -just as any C++ object interface is declared. If you think of an object as -an abstract concept that should be implemented by derived classes, by all -means, use the Abstract Base Class approach to interface declaration. If you -think that an object should be completely concrete and you foresee no need -to ever modify its behavior, feel free to avoid declaring any methods virtual. -If you think that an object could be useful as a base class, feel free to -declare its methods virtual. If you like to use the PIMPL idiom, again, feel -free. If you want to use any combination of these techniques, feel free. -We make no restrictions. - -@cindex API -When we speak of an ns-3 interface, we do not worry about interface definition -languages, or pure virtual classes, or registries we just think about C++ -object declarations and their associated methods. We tend to think of -interfaces to objects as simply a private or public API. When we instantiate -an @command{ns-3} interface, it is the C++ object model that dictates how that -object is brought into existence. When a method is called on an @command{ns-3} -Interface, it is the C++ object model that dictates how that method is -dispatched. - -We do, however, provide a base class that endows vanilla C++ objects with -capabilities that can be seen as conceptually similar to those provided by -Microsoft Component Model @emph{Interfaces}. - -@section The Ns-3 Object and GetObject -@cindex Component Object Model -One thing that Microsoft arguably got right in the Component Object Model was -the idea of Interface aggregation and discovery via QueryInterface. We have -embraced these ideas in @command{ns-3}. This was done primarily to address a -common problem in large software systems. A good example of this problem -happens in the @command{ns-3} Node class. - -@cindex OOP -@cindex weak base class -@cindex base class bloat -@cindex Swiss Army Knife class -@cindex Node -If one were to take the standard OOP view of specializing a @code{Node} into -an internet host, for example, one would typically inherit from the @code{Node} -base class and include functionality to implement such things as internet -routing and a TCP/IP protocol stack. Other types of @code{Node}s might -inherit from the node class and specialize in different ways, or further -specialize the internet host class, treating it as a base class. This can -result in a complicated inheritance tree in which some specializations are -simply not available to other branches of the tree which can make reuse -difficult or impossible. This is known as the @emph{weak base class} problem -and creates pressure to drive functionality up the inheritance tree into the -base classes. This, in turn, results in @emph{base class bloat} and the -resulting @emph{swiss army knife} base classes which end up trying to do -everything in one place. - -Even if one successfully avoided these swiss army knife base classes, one -would also want to be able to treat new specializations of @code{Node} -generically in the system. This means one would pass references to the base -class (@code{Node}) across public APIs. This introduces @emph{upcasts} prior -to passing across public APIs and corresponding @emph{downcasts} on the other -side in order to gain access to required specialized functions. As the -inheritance tree becomes more complicated, this approach can cause another -related problem known as the @emph{fragile base class} problem. This happens -when changes to the base class cause unexpected problems in the various and -sundry subclasses. - -These effects seem always to result in a positive feedback loop driving -everything into the base class and destroying much of the encapsulation which -is a hallmark of the object oriented approach. - -@subsection Interface Composition -@cindex Node -There is a completely different way to address the Node specialization -problem. Instead of approaching the situation using inheritance, one can -look at the problem as one of composition. We can look at the @code{Node} -class as a container of sorts that holds other objects. In this case, the -objects would be instances of the classes implementing the internetwork -routing code, or the TCP/IP protocol stack described above. This approach -preserves the encapsulation and solves the weak base class, base class bloat -and fragile base class problems; but the question of method dispatch -immediately comes to mind. - -@cindex delegation -In many systems, @emph{delegation} is used. The base class, @code{Node}, -in this approach would provide methods that simply forward to the objects -implementing the desired functionality. This situation clearly does not -address the base class bloat problem since dispatch methods must be added -to the base class. The situation is mitigated somewhat by pushing the -implementation of the dispatch methods to contained objects, but the -fundamental problems are still present. What is really needed is a way -to compose objects but at the same time keep the interfaces to those -objects separated. - -@cindex aggregation -Composition, usually called @emph{aggregation}, along with runtime Interface -discovery is the solution that Microsoft originally championed and that -@command{ns-3} has adopted --- albeit with many simplifications and a few name -changes. - -@subsection Objects and Interfaces -@cindex COM -@cindex QueryInterface -Now that we have mentioned Microsoft COM and are almost obligated to mention -the terms Interface and QueryInterface. For those familiar with COM, loosely -speaking, QueryInterface is to COM as GetObject is to @command{ns-3}. -The analogy, while good conceptually, is superficial from an implementation -point of view. - -@cindex Node -Addressing our current example of a @code{Node}, generically speaking, each -node needs to aggregate an object that will implement internetwork routing -and TCP/IP. The system will need to provide a mechanism for locating the -aggregated objects and allow a client to discover them. - -@cindex aggregation -@cindex Object -These aggregated objects have interfaces in the C++ sense of collections of -method signatures. In @command{ns-3}, when objects are capable of -participating in this aggregation process, they are called @command{ns-3} -@code{Objects}. @code{Objects} receive the functionality required for this - participation by inheriting from the @command{ns-3} base class @code{Object}. - -Note well that when we write the word @code{Object} (note the uppercase 'O' in -the spelling and the change of font) we are referring to a kind of C++ object -that has inherited the capability of participating in an aggregation. The -@command{ns-3}-specific word @code{Object} can have a significantly different -meaning than that of a vanilla C++ object outside the aforementioned -inheritance tree, and the difference is only readily apparent via context. -In this tutorial we will always write the @command{ns-3}-specific kind of -@code{Object} in a fixed font; and will write the vanilla C++ term object in -normal font. In conversation, you will need to be careful to understand which -term is meant: object or @code{Object}. - -Once an object has inherited from class @code{Object} it has the ability to -@emph{host} an aggregation. This means that it has the ability to add other -@code{Objects} to its aggregation via the method @code{AggregateObject}. It -also means that it can provide a service to @emph{discover} other objects in -its aggregation via the method @code{GetObject}. - -@cindex base class -Technically, the class named @code{Object} is simply a base class that you -will inherit from if you want your @code{Objects} to support aggregation and -discovery. Many systems have a base class that implements common -functionality and these base classes are typically called something like -Object. The @command{ns-3} version of this base class relates primarily to -@code{Object} aggregation and discovery, although it does also provide methods -to help with intrusive reference counting and tracing as well. - -When a C++ object inherits from the ns-3 Object base class, it is conceptually -promoted to an ns-3 @code{Object} irrespective of how the object was declared -(e.g., as an abstract base class, concrete class, with virtual methods, etc.). -In ns-3, you should associate inheritance from the class named @code{Object} -with promotion of an object to the status of some locatable @code{Object} -rather than with the form of the class declaration. - -@cindex COM -@cindex CORBA -@cindex ORBit -For those of you unfamiliar with Microsoft COM, CORBA or ORBit, this might -sound obvious. For those of with such a background, the point we are making -is that there is no such thing in @command{ns-3} as a separate Interface -declaration, no such thing as an Interface Definition Language, no such thing -as a UUID or GUID, etc. In @command{ns-3} we just work with C++ objects that -may be given some very useful abilities by inheriting from the @command{ns-3} -base class @code{Object}. @command{Ns-3} @code{Objects} are not required to -inherit from classes composed of pure virtual methods in order to define an -Interface. It's all really just ``plain old C++.'' - -To summarize, when you instantiate an object that inherits from the -@code{Object} class, you will have a C++ object that has four important -properties: - -@cindex AggregateObject -@cindex GetObject -@itemize @bullet -@item The @code{Object} has a C++ interface defined by the collection of method signatures in its inheritance tree; -@item The @code{Object} has some way to identify its underlying class uniquely; -@item The @code{Object} is a kind of container that has the ability to aggregate other @code{Objects} using the method @code{AggregateObject}; -@item The @code{Object} exports a method called @code{GetObject} that allows for discovery of other aggregated @code{Objects}. -@end itemize - -@cindex base class -@cindex Object -It is crucially important to understand what we have described here -(especially for those coming from other systems that provide similar -functionality). A given C++ class has an object access interface that is -essentially the collection of method signatures specified in its inheritance -tree. This is a C++ object model thing. Ns-3 provides a base class from -which the class in question can inherit and be promoted to the status of -@code{Object}. Once a class becomes an @code{Object} it has inherited the -ability to aggregate and search for other @code{Objects} that are added to -its aggregation. - -That last detail is important. In @command{ns-3} @code{Objects} are both -containers and specifications for a object method access. We have previously -mentioned that the @code{Node} class acts as a container. In fact, the -@code{Node} class inherits from @code{Object} and is itself an @command{ns-3} -@code{Object}. So, when the @code{Node} object is created it is really an -aggregation of one @code{Object} and you can call @code{AggregateObject} or -@code{GetObject} on the resulting @code{Node} object. Along with being an -aggregation, the @code{Node} class also describes a public interface. This -public interface (API) is declared just as any C++ object is declared, via its -class methods as specified in the inheritance tree. For those steeped in -COM or CORBA, this is where the concept of Interface works in @command{ns-3}. -Remember that it is generally true that @code{Objects} are both aggregations -and APIs. - -@subsection Aggregations -@cindex aggregate -The figure below shows how an @code{Object} could be illustrated in detail. -The line with the circle at the top of the diagram represents the appearance -of the @code{Object} API to the external world. This circle and line are -together called a lollipop because of its superficial similarity to a kind of -childs candy. - -@sp 1 -@center @image{oneobj,,,,png} - -@cindex API -You could declare this API and associated @code{Object} quite simply using a -non-virtual class as follows, - -@verbatim - class A : public Object { - public: - static ns3::TypeId GetTypeId (void) - { - static ns3::TypeId tid = ns3::TypeId ("A") - .SetParent (Object::GetTypeId ()) - .AddConstructor (); - return tid; - } - - A () - { - } - - void MethodA (void); - }; -@end verbatim - -The methods that are then available via the API labeled @code{A} in the -figure above are the methods inherited from the @code{Object} base class -(@code{GetObject}, @code{Ref}, and @code{Unref}) and those from class -@code{A} (@code{MethodA}). - -Note that you must declare a @code{TypeId} in your @code{Object} class, and -it must be declared static to make it class-wide in scope. This @code{TypeId} -is a unifying element in the @command{ns-3} object model and uniquely -identifies @code{Objects} at run-time as being instantiated from a particular -class. We'll have much more to say about @code{TypiId} shortly. - -You can think of the arc and arrow device coming off each side of the -illustrated @code{Objects} as part of a connector. These connectors allow -@code{GetObject} to search aggregations for an instance of a class type. -The figure below shows an aggregation of three @code{Objects}: A, B and C. -The class declarations for classes @code{B} and @code{C} are substantially -similar to that of class @code{A}. - -@sp 1 -@center @image{threeobj,,,,png} - -You can visualize these @code{Objects} as being snapped together like Lego -building blocks if you like. When @code{Objects} are aggregated, a -@code{GetObject} search path is formed through the connectors. In order -to create this aggregation you will first need to create the @code{Objects}. -These are just normal, everyday C++ objects that we can create using the -@code{CreateObject} template function and manage using smart pointers. The -following code should be obvious to you by now: - -@verbatim - Ptr a = CreateObject (); - Ptr b = CreateObject (); - Ptr c = CreateObject (); -@end verbatim - -@cindex aggregation -When you create an aggregation, you pick one of the @code{Objects} of the -aggregation to think of as the container. In this case well pick @code{Object} -A. In order to aggregate an @code{Object}, you simply call the method -@code{AggregateObject} that your class has inherited from class @code{Object}. -The following code will aggregate @code{Object B} and @code{Object C} onto -the @code{Object} (and container/aggregation) @code{A}. - -@cindex AggregateObject -@cindex GetObject -@cindex Object -@verbatim - a->AggregateObject (b); - a->AggregateObject (c); -@end verbatim - -Thats all there is to it. Now that you have those connectors snapped -together, you can ask each of the @code{Objects} in the aggregation for any of -the other @code{Objects} in the aggregation. Lets look at a simple example: - -@verbatim - Ptr newB = a->GetObject (); -@end verbatim - -Now, the explanation of what this snippet does is not as simple as writing it. -The left hand side of this assignment declares a smart pointer to the class -@code{B} to help with memory management of the returned @code{Object} pointer. -You should be very familiar with smart pointers at this stage of the tutorial. - -The right hand side illustrates how @code{GetObject} is acutally used. -The method @code{GetObject} is templated. The assocated template parameter -(between the brackets) specifies the @emph{class} that is being requested. -This is important. Since it is the class type that specifies the search -criterion, there can be only one instance of a particular class present in an -aggregation. Looking back a little, although the parameter to -@code{AggregateObject} appears to be a vanilla C++ object (@code{b} or @code{c} -above), it actually represents (is an instance of) a class that has an -associated @code{TypeId} and inherits from @code{Object}. When you call -@code{GetObject} you specify the search criterion (using the template -parameter) as a class name. This referenced class must also have an -associated @code{TypeId} and must also have inherited from @code{Object}. - -This may be summarized by saying that @code{AggregateObject} takes an -@emph{instance} of an object of a particular class that inherits from -@code{Object}. GetObject looks for a @emph{class} of a particular type -(that again inherits from @code{Object}) and possibly returns an aggregated -object instance of that type. - -Now that you have those conceptual connectors snapped together, you can ask -each of the @code{Objects} in the aggregation for any of the @code{Objects} -in the aggregation. For example we could walk the @code{Objects} asking each -for the next in the aggregation. First we would ask the @code{Object} pointed -to by the smart pointer @code{a} to look for the @code{Object} @code{class B}: - -@verbatim - Ptr newB = a->GetObject (); -@end verbatim - -Next, we can ask the @code{Object} pointed to by the smart pointer @code{newB} -to look for the @code{Object} representing @code{class C}: - -@verbatim - Ptr newC = newB->GetObject (); -@end verbatim - -@cindex Object -Then, we can ask the @code{Object} pointed to by the smart pointer @code{newC} -to look for the @code{Object} representing @code{class A} and complete our -circuit of the aggregation: - -@verbatim - Ptr newA = newC->GetObject (); -@end verbatim - -@cindex GetObject -@code{GetObject} has some important properties that we need to go over. -Technically, @code{GetObject} is a @emph{symmetric}, @emph{reflexive} and -@emph{transitive} operation with respect to the set of aggregated -@code{Objects}. - -@subsubsection Symmetry -@cindex symmetry -The symmetric nature of @code{GetObject} guarantees that if one performs a -@code{GetObject} on a given @code{Object} for the class of that same -@code{Object}, that @code{GetObject} must succeed. In other words, the -fact that you accessed the aggregation via an instance of an @code{Object A} -in the aggregation implies the reachability of that @code{Object} in the -aggregation. This is usually written (by Microsoft) as, - -@center must succeed (A >> A) - -We can illustrate this property with the code snippet, - -@verbatim - Ptr symmetricA = a->GetObject (); - NS_ASSERT (symmetricA); -@end verbatim - -Here we take as given an interface (smart) pointer --- named @code{a} --- on -which we perform a @code{GetObject} looking for the class that represents that -same @code{Object}. This call must always succeed and a smart pointer to the -aggregated instance of that class is returned. - -@subsubsection Reflexivity -@cindex reflexivity -Calls to @code{GetObject} must also be reflexive. This means that if you -successfully @code{GetObject} for @code{Object B} from @code{Object A}, then -you must always be able to @code{GetObject} for @code{A} from @code{B}. This -is usually written as, - -@center must succeed (A >> B, then B >> A) - -This property can be illustrated with the code snippet, - -@verbatim - Ptr b = a->GetObject (); - Ptr reflexiveA = b->GetObject (); - NS_ASSERT (reflexiveA); -@end verbatim - -If the first @code{GetObject} on @code{Object A} looking for @code{Object B} -succeeds, then a @code{GetObject} on @code{Object B} looking @code{Object A} -must succeed. - -@subsubsection Transitivity -@cindex transitivity -@code{GetObject} must also be transitive. This means that if one can -find @code{Object B} from @code{Object A}, and @code{Object C} from -@code{Object B}, then one must also be able to find @code{Object C} from -@code{Object A}. This is usually written as, - -@center must succeed (A >> B, and B >> C, then A >> C) - -This property can be illustrated with the code snippet, - -@verbatim - Ptr b = a->GetObject (); - Ptr c = b->GetObject (); - Ptr transitiveC = a->GetObject (); - NS_ASSERT (transitiveC); -@end verbatim - -If you can get to @code{Object B} from @code{Object A}, and you can get to -@code{Object C} from @code{Object B}, then a @code{GetObject} on -@code{Object A} looking for @code{Object C} must also succeed. - -@subsection Creating the TypeId -@cindex TypeId -@cindex GetTypeId -The final piece of this puzzle is the @code{TypeId}. Recall that the -declaration our example object above included the following code - -@verbatim - static ns3::TypeId GetTypeId (void) - { - static ns3::TypeId tid = ns3::TypeId ("A") - .SetParent (Object::GetTypeId ()) - .AddConstructor (); - return tid; - } -@end verbatim - -This is the bit of code that ties this all together. For those unfamiliar -with the idioms involved, this declaration can be rather dense. First, let's -examine the function declaration itself. The following code, - -@verbatim - static ns3::TypeId GetTypeId (void) ... -@end verbatim - -declares a function that will be associated with all of the instances of the -given class. This is a function, not a method, in that it can be accessed -without a @emph{this} pointer; but it is associated with the class in a -namespace sense. The use of this kind of declaration allows one to write, - -@verbatim - return A::GetTypeId (void); -@end verbatim - -if the @code{TypeId} is needed for our @code{class A}. More generically the -class name can be substituted in a template, as is done deep in the -@command{ns-3} object system. - -From this perspective, if you leave out the middle of the function definition, -the boundaries should make sense to you. - -@verbatim - static ns3::TypeId GetTypeId (void) - { - return tid; - } -@end verbatim - -@cindex function-local variable -You are obviously looking at a global function associated with your class -that simply returns a @code{TypeId}. Now, what about the rest. The code - -@verbatim - static ns3::TypeId tid = ns3::TypeId ("A") - .SetParent (Object::GetTypeId ()) - .AddConstructor (); -@end verbatim - -when found inside the function declaration is called a function-local variable -with associated initialization. It'll be easier to pick this statement apart -piece by piece as well. The first line, - -@verbatim - static ns3::TypeId tid = ... -@end verbatim - -is the declaration of the function-local variable tid. This is essentially -an initialized global variable, the scope of which has been reduced to within -the enclosing method. You can think of this as a kind of global variable -that can only be accessed right there where it is created. If the variable -is initialized, this amounts to the same behavior as if a global static -initializer was declared in a namespace of the same name as your class. -Global static initializers are guaranteed by the C++ language definition to -be executed before your main procedure is entered. So are function-local -variables. - -The variable that is being initialized is of type @code{ns3::TypeId}, is -named @code{A::tid} since it is inside the class declaration for -@code{class A}, and is initialized by a call to the constructor for the class -@code{TypeId}. The constructor for @code{TypeId} takes a @code{std::string} -that can be used to locate the type information for your class. We usually -privide the class name as the string. - -Hopefully, this much of the declaration is now clear: - -@verbatim - static ns3::TypeId GetTypeId (void) - { - static ns3::TypeId tid = ns3::TypeId ("A") - ... - return tid; - } -@end verbatim - -All that is left now are the lines including @code{SetParent} and -@code{AddConstructor}. - -@verbatim - static ns3::TypeId tid = ns3::TypeId ("A") - .SetParent (Object::GetTypeId ()) - .AddConstructor (); -@end verbatim - -The last bit may seem quite odd at first glance, but don't let the way the -code is broken up over several lines throw you. If you saw something like, - -@verbatim - pointer->TypeId()->SetParent()->AddConstructor(); -@end verbatim - -you probably wouldn't hesitate at all. Clearly, you would think, a method -called @code{TypeId} is called using the pointer called @code{pointer} as -shown below. - -@verbatim - pointer->TypeId() -@end verbatim - -The method @code{TypeId} must further return a pointer to an object that has -a method called @code{SetParent}. Just as clearly, @code{SetParent} must -return a pointer to an object that has a method called @code{AddConstructor}. -The same sort of thing is happening in our code snipped, except we are using -references instead of pointers. Perhaps if we rearrange this code to live on -one line it will be clearer. - -@verbatim - ns3::TypeId ("A").SetParent (Object::GetTypeId ()).AddConstructor (); -@end verbatim - -It's just a string of method calls. The remaining question is then, what do -those three methods do. - -The first, @code{ns3::TypeId ("A")}, simply allocates a new type in the system -and allows you to refer to it in the future by a string. We have mentioned -inheritance trees often in the previous discussion. The second method, -@code{SetParent} associates the class being defined with its parents in the -tree. Finally, the @code{AddConstructor} method allows you to specify a -constructor to be used when an instance of your class is created using -@code{CreateObject}. - -@verbatim - AddConstructor (); -@end verbatim - -You can interpret this as explaining to the @command{ns-3} object system that -you have a constructor named @code{A::A} which takes no parameters. You are -saying that this constructor should be used when @code{CreateObject} is called -with no parameters. - -By including the structure of the inheritance tree, in @command{ns-3} we can -use implementation inheritance to easily create new @code{Objects}. You are -prevented from doing so in Microsoft COM, but this was almost universally -identified as a problem. - -So, looking at the entire @code{GetTypeId} declaration again, - -@verbatim - static ns3::TypeId GetTypeId (void) - { - static ns3::TypeId tid = ns3::TypeId ("A") - .SetParent (Object::GetTypeId ()) - .AddConstructor (); - return tid; - } -@end verbatim - -it should be clear what is happening. - -@subsection A Very Real Example -@cindex Node -@cindex AggregateObject -@cindex GetObject -@cindex Object -At this point you may be asking yourself what the point of all of this is, -since you already had those pointers laying around when you created the -objects. The typical case is that one will create and aggregate some number -of @code{Objects} in a constructor and return only a pointer to a single -@code{Object} as in our canonical example with @code{class Node}. In this -case, the @code{Node} would be created and the @code{Node} constructor might -create and call @code{AggregateObject} to aggregate the @code{Objects} for -internetwork routing and TCP/IP. From an external point of view, these -aggregated objects may be discovered at run-time using @code{GetObject}. - -Generally one tends to think of one of the @code{Objects} in the aggregation -as being the container and other @code{Objects} being aggregated to that -container. In the case of a Node, for example, it is quite natural to think -of the Node as being the container which contains protocol stacks, internet -routing, etc. So, lets start thinking about a real example by calling the -container @code{Object Node} instead of @code{A} as we have been. The -creation of this @code{Object} is found all over our example programs. For -example, you will find code like the following in -@code{samples/simple-point-to-point.cc}: - -@verbatim - Ptr n = CreateObject (); -@end verbatim - -It may appear obvious to you now that the @code{InternetNode} class name -provided to the template function @code{CreateObject} means that -@code{InternetNode} is an @command{ns-3} @code{Object} and you will be able to -call @code{GetObject} on the resulting smart pointer. Well, I'm afraid that's -not entirely true. It's slightly more complicated. - -Take a look at @code{src/internet-stack/internet-stack.h} and find the class -declaration for @code{InternetNode}. - -@verbatim - class InternetNode : public Node - { - public: - InternetNode(); - ... - }; -@end verbatim - -@cindex GetTypeId -@cindex TypeId -@cindex Object -There is no declaration of a @code{static TypeId GetTypeId (void)} in this -class. This means that the @code{InternetNode} is really not an @code{Object} -for which you can @code{GetObject}. It turns out that the @code{InternetNode} -is an @emph{implementation class} of the @code{Node Object}. - -You may recall that there can be an implicit cast in a smart pointer -assignment if the cast is to a visible, unambiguous base class. That is, in -fact, what is happening here. Now, take a look at @code{src/node/node.h} and -find the class declaration for @code{class Node}. There you will find, - -@verbatim - class Node : public Object - { - public: - static TypeId GetTypeId (void); - ... - }; -@end verbatim - -Class @code{InternetNode} inherits from class @code{Node} that, in turn, -inherits from class @code{Object}. It is @code{Node} that provides a -@code{GetTypeId} method. Therefore it is @code{Node} that is an -@command{ns-3} @code{Object}. Note well that @code{InternetNode} is not an -@code{Object} in the sense that one should call @code{GetObject} on an -aggregation looking for an @code{InternetNode} class. That is, you should not -do, - -@verbatim - Ptr i = node->GetObject (); -@end verbatim - -since there really is not InternetNode::GetTypeId. It is @code{Node} that is -the @emph{proper} @code{Object} in this case and you should view -@code{InternetNode} as an implementation of the @code{Node Object}. This may -become clearer as we look a little deeper. - -We spoke of a protocol stack that is aggregated to a @code{Node} in our -discussions above, what we see in the real @command{ns-3} code is that this -is represented by the @code{Ipv4 Object}. If you look in -@code{src/node/ipv4.h} you will find, - -@verbatim - class Ipv4 : public Object - { - public: - static TypeId GetTypeId (void); - ... - }; -@end verbatim - -Since class @code{Ipv4} inherits from class @code{Object} and has a -@code{GetTypeId}, it is an @command{ns-3} @code{Object}. If you look in -@code{src/node/ipv4.cc} you will find, - -@verbatim -TypeId -Ipv4::GetTypeId (void) -{ - static TypeId tid = TypeId ("Ipv4") - .SetParent (); - return tid; -} -@end verbatim - -After all of this reading you know that this code snippet is asking the -system to create a unique @code{TypeId} for the @code{Ipv4} class and -declares that @code{Ipv4} inherits from class @code{Object}. This is what -makes an @code{Ipv4} an @code{Object}. - -@cindex Ipv4 -It turns out that the Ipv4 class is an abstract base class (ABC). There are -a number of pure virtual methods declared in that class. This means that -an @code{Ipv4} object may not be instantiated. This is reflected by the fact -that there are no constructors registered in the @code{GetTypeId} method above. -What is instantiated in the real system is an implementation class, called -@code{Ipv4Impl}. This class inherits from @code{Ipv4} and provides the -required virtual methods. This is where understanding what is an -@code{Object} and what is not can get tricky. The @code{Object} is the -@code{Ipv4} class since that is where the @code{GetTypeId} is found. The fact -that you see @code{GetTypeId} there tells you that the @code{Ipv4} class is -the class for which you can @code{GetObject}. - -@cindex implementation class -The class @code{Ipv4Impl} provides an implementation for the pure virtual -methods in @code{Ipv4}. Since class @code{Ipv4} cannot be instantiated, one -instantiates the @code{Ipv4Impl} class to create an @code{Ipv4} @code{Object}. -You will use the @code{CreateObject} template function to create an object that -implements the methods of an @code{Object}. You can probably see how this -gets even more tricky in conversation. - -Once the @code{Ipv4Impl} object is instantiated, the resulting pointer is -immediately cast to an @code{Ipv4} pointer. Clients will then use the -methods specified in the @code{Ipv4} class to access the @code{Ipv4 Object} -methods which are, in turn, implemented in the @code{Ipv4Impl} object. - -If you now look in the file, @code{src/internet-stack/internet-stack.cc} you -will see the following code in @code{InternetNode::Construct} that creates the -@code{Ipv4} Interface and aggregates it. - -@verbatim - Ptr ipv4Impl = CreateObject (ipv4); - ... - Object::AggregateObject (ipv4Impl); -@end verbatim - -Note that the parameter @code{ipv4} passed to the @code{CreateObject} template -function is actually a pointer to an @code{Ipv4L3Protocol} which you can -ignore at this point --- it doesn't really have anything to do with the -@code{Ipv4} Interface. - -This is exactly the same thing that is happening in the case of the -@code{InternetNode}. - -@verbatim - Ptr n = CreateObject (); -@end verbatim - -@cindex implementation object -@code{CreateObject} is being called to create an implementation object, -in this case @code{InternetNode}, which implements the methods of the -@code{Node Object}. It is the resulting @code{Node Object} which you would -use as the container and it is the @code{Node} class that you would use as -the template parameter when calling @code{GetObject}. In the same way, you -would @emph{not} want to do, - -@verbatim - Ptr ipv4 = node->GetObject (); -@end verbatim - -Rather you should understand that the @emph{proper} @code{Object} is the -@code{Ipv4} not the @code{Ipv4Impl} and do the following, - -@verbatim - Ptr ipv4 = node->GetObject (); -@end verbatim - -@cindex CreateObject -This does illustrate that the fact that whether an object created by -@code{CreateObject} is or is not an @code{Object} in the usual sense can be -quite well hidden if you are casually looking at the object creation code. -The designers of the system had long and involved discussions on this issue -and in the end decided that mnemonic aids such as Hungarian notation were a -stylistic thing and you should just refer to the system documentation to -determine what objects are @command{ns-3} @code{Objects} and what the APIs -of those @code{Objects} actually are (RTFM --- as in Read the Fine Manual, -of course). - -@cindex AggregateObject -@cindex Object -In the case of @code{Ipv4Impl}, you know that the class inherits somehow -from @code{Object} since there is a call to @code{AggregateObject} that -refers to an instance of an @code{Ipv4Impl}. You will have to go to -the header file @code{src/internet-stack/ipv4-impl.h} and find that -@code{Ipv4Impl} inherits from class @code{Ipv4}. You will then have go to -the file @code{src/node/ipv4.h} and see that it inherits from @code{Object} and -defines a @code{GetTypeId}. Thus the @code{Object} for which you can -@code{GetObject} is really the @code{Ipv4 Object}. - -Returning to some real @command{ns-3} example code, lets take a look at -@code{examples/simple-point-to-point.cc}. You will find the following -code in this file: - -@verbatim - Ptr n0 = CreateObject (); - ... - Ptr ipv4; - ipv4 = n0->GetObject (); - ipv4->SetDefaultRoute (Ipv4Address (``10.1.1.2''), 1); -@end verbatim - -@cindex InternetNode -@cindex Node -@cindex Object -@cindex GetObject -The first line creates an @code{InternetNode} implementation object and casts -the resulting smart pointer to a @code{Node} as we have discussed extensively. -The next line shown declares a smart pointer to an @code{Ipv4 Object}. We -then do a @code{GetObject} on the @code{Node} looking for the -@code{Ipv4 Object}. You know since you've read every line of this tutorial -in detail exactly how that @code{Ipv4 Object} got into every @code{Node}. You -know that the @code{GetObject} will return a smart pointer to its aggregated -@code{Ipv4} Interface. Once we have the @code{Ipv4} smart pointer, we simply -use it as if it were any other C++ object. The last line shows this by -setting the default route for the node. - -@section Caveats -There are a few things that you should remember but which may not be -immediately obvious. - -@subsection Ns-3 Objects are Associated with Classes not C++ objects -@cindex Object -@cindex GetObject -@cindex iterate -@cindex aggregation -@cindex GetNDevices -Okay, you can see some of the problems with the terminology popping up again. -We are reminding you that when you do a GetObject you are providing the key -to the lookup by giving a class name and not anything that is unique to a -C++ object. - -You cannot add more than one @code{Object} of a given type (class name) to an -aggregation. If you need to contain a number of @code{Objects} of the same -type in the same aggregation, you will need to provide a separate container -over which you can iterate. For example, the @code{Node} class provides -methods, - -@verbatim - uint32_t GetNDevices (void) const; - Ptr GetDevice (uint32_t index) const; -@end verbatim - -that are used iterate over the multiple @code{NetDevice} @code{Objects} -associated with it. - -@emph{Remember: Object types do not identify objects.} - -@subsection Dont use GetObject to Check Your Own Type. -@cindex GetObject -It is tempting to use @code{GetObject} as a form of runtime type -information. Dont do it. You have no control over what @emph{other} -object may be added to your aggregation. Someone else may have -appropriated (reimplemented) your type and aggregated themselves onto the -aggregation. - -Consider a socket factory implementation. Sockets can be either UDP sockets -or TCP sockets. A socket factory will have a generic @code{SocketFactory} -Object and either a UDP specific interface for setting UDP parameters or a -similar TCP-specific interface. - -Consider what might happen if you declared your socket factory as a partially -abstract base class, and then provided separate implementations for UDP and -TCP specific methods of this factory in separate concrete classes. Now -consider what might happen if you used @code{GetObject} in your base class -to determine if you were a UDP or a TCP factory. - -If a factory, say the UDP version, were not aggregated to any other -@code{Object}, the base class could @code{GetObject} on itself for the -UDP-specific class name. If the @code{GetObject} succeeded, it could then -infer that it was a UDP implementation and would then do any UDP-specific -tasks it could. [Experienced C++ folks are cringing about how -horrible this design is, but bear with me --- its a simple illustration of -a specific and perhaps not-too-obvious problem.] - -If another factory, say the TCP version, were not aggregated to any other -Interface, the base class could @code{GetObject} on itself for the UDP-specific -interface. If this failed, it could then infer that it had a TCP -implementation and would then do any TCP-specific tasks it could. - -Now, what happens when these two working objects are aggregated together by -some innocent end-user. Since the @code{Objects} are conceptually snapped -together, the TCP implementation would suddenly begin finding the UDP -Interface from the other class factory and think it was the UPD implementation. - -@emph{Objects should not be used as run-time type information.} - -@section Connecting the Dots -@cindex Object -@cindex GetObject -@cindex AggregateObject -@cindex GetTypeId -@cindex API -This may all sound very complicated to you if this is your first exposure to -these concepts. It may be annoying if I tell you that its really not as hard -as it sounds. Rest assured that if you take some time, look at and understand -the examples and write a little test code it will all come together for you. -Grep around the system for @code{AggregateObject} and @code{GetObject} and -take a look at how we have used them. This will also give you a good idea of -what our core @code{Objects} and associated APIs are. If you grep for -@code{GetTypeId} you will find most, if not all of the @code{Object} API -interface declarations in the system. The more you see this idiom in -use, the more comfortable you will be with the idea and the more you will see -how this addresses the weak base class, swiss army knife base class, and -fragile base class problems I explained at the beginning. - -As I alluded to earlier, the developers had long discussions regarding how to -make navigating the @code{Object} environment easier. The primary issue was -how we could make it easier to convey to you, the model writer, that an object -was an @code{Object}. We originally used similar terminology as Microsoft -COM and used QueryInterface instead of @code{GetObject}. One suggestion was -to adopt the convention that classes that implemented Interfaces must begin -with the letter I. Microsoft does this, as exemplified by the class IUnknown. -We also toyed with the idea of beginning our header files with ``i-'' as in -``i-ipv4.h.'' We considered forcing some structure on Interfaces with a pure -virtual class specification, the names of which begin with an I; and -corresponding implementations, the names of which begin with a C. This all -got out of hand fairly quickly. - -In the end we decided that we were really discussing issues of programming -style, and we really could not come up with a strong reason to impose any -particular solution. No matter what direction we took, we ended up with some -form of extra confusion or extra complexity somewhere in the system. The -resulting system is extremely flexible and easy to use. It is, unfortunately, -sometimes hard to document and talk about. - -@cindex Feynman -If it helps you to think in terms of Microsoft COM and Interfaces, by all means -do so, just be aware that even though @command{ns-3} @code{Objects} descend -from COM in some sense, there are subtle differences that may get you lost or -into trouble. So to paraphrase Feynman one more time, - -@quotation -``@command{Ns-3} @code{Objects} do not behave like COM Components, or Java -Beans, or CORBA objects, or clouds or weights on springs, or like anything -that you have ever seen --- they are @command{ns-3} components.'' -@end quotation - -Just get very familiar with the @command{ns-3} object model. It is the heart -of the system and if you do not understand it you will not understand how to -write an @command{ns-3} model properly. - -@c ======================================================================== -@c Doxygen -@c ======================================================================== - -@node The-Doxygen-Documentation-System -@chapter The Doxygen Documentation System - -@node How-To-Change-Things -@chapter How to Change Things - -@node How-To-Set-Default-Values -@chapter How to Set Default Values - -@node How-To-Write-A-New-Application -@chapter How to Write a New Application - diff -r c9133c87760d -r 7ff69b244b5b doc/tutorial/in-process/output.texi --- a/doc/tutorial/in-process/output.texi Sun Jan 02 22:57:04 2011 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,462 +0,0 @@ - -@c ======================================================================== -@c Simulation Output -@c ======================================================================== - -@node Simulation Output -@chapter Simulation Output - -At this point, you should be able to execute any of the built-in -programs distributed with @command{ns-3}. Next, we will look at -how to generate and tailor the simulation output, before turning -to how to modify simulation scripts to do different things. - -@node Tracing Basics -@section Tracing Basics - -The whole point of simulation is to generate output for further -study, and the @command{ns-3} tracing system is a primary -mechanism for this. -Since @command{ns-3} is a C++ program, standard facilities for -generating output from C++ programs apply: - -@verbatim -#include -... -int main () -{ - ... - std::cout << "The value of x is " << x << std::endl; - ... -} -@end verbatim - -The goal of the @command{ns-3} tracing system is to -provide a structured way to configure the simulator to output results -in standard or modifiable formats. -@itemize @bullet -@item For basic tasks, the tracing system should allow the user to -generate standard tracing for popular tracing sources, and to customize -which objects generate the tracing. -@item Intermediate users will be able to extend the tracing system to -modify the output format generated, or to insert new tracing sources, -without modifying the core of the simulator. -@item Advanced users can modify the simulator core to add new -tracing sources and sinks. -@end itemize - -The @command{ns-3} tracing system is fundamentally built on the -concept of separating tracing sources from sinks. -@enumerate -@item Trace sources (e.g., provide access to every packet received) -@item Trace sinks (e.g., print out the packet) -@item A mechanism to tie together sources and sinks -@end enumerate -The rationale for this division is to allow users to attach new -types of sinks to existing tracing sources, without requiring -users to edit and recompile the core of the simulator. -Thus, in the example above, a user could write a new tracing sink -and attach it to an existing tracing source. What remains to -be defined is a way for users to find these hooks (tracing sources) -and attach sinks to them. A new tracing namespace is defined for -this purpose. - -We will first walk through how some pre-defined sources and sinks -are provided and may be customized with little user effort. We -return later in this chapter to advanced tracing configuration including -extending the tracing namespace and creating new tracing sources. - -@subsection ASCII tracing -@cindex ASCII -For Internet nodes, the ASCII trace wrapper is a wrapper around -the @command{ns-3} low-level -tracing system that lets you get access to underlying trace events easily. -The output of a trace of a simulation run is an ASCII file --- thus the name. -In the spirit of keeping things simple, you won't be able to control or -configure the output at this stage. - -For those familiar with @command{ns-2} output, this type of trace is -analogous to the @command{out.tr} generated by many scripts. - -@cindex tracing packets -Let's just jump right in. As usual, we need to include the definitions -related to using ASCII tracing (don't edit any files quite yet): - -@verbatim - #include "ns3/ascii-trace.h" -@end verbatim - -We then need to add the code to the script to actually enable the ASCII tracing -code. The following code must be inserted before the call to -@code{Simulator::Run ();}: - -@verbatim - AsciiTrace asciitrace ("tutorial.tr"); - asciitrace.TraceAllQueues (); - asciitrace.TraceAllNetDeviceRx (); -@end verbatim - -The first line declares an object of type @code{AsciiTrace} named -@code{asciitrace} and passes a string parameter to its constructor. This -parameter is a file name to which all of the trace information will be written. -The second line, @code{asciitrace.TraceAllQueues ();} asks the trace object to -arrange that all queue operations (enqueue, dequeue, drop) on the queues -in all of the nodes of the system be traced. On the receive side, -@code{asciitrace.TraceAlllNetDeviceRx ()} traces packets received by -a NetDevice. For those familiar with @command{ns-2}, these are equivalent -to the popular trace points that log "+", "-", "d", and "r" events. - -Try running the following program from the command line: -@verbatim - ./waf --run tutorial-csma-echo-ascii-trace -@end verbatim - -@cindex tutorial.tr -Just as you have seen previously, you will see some messages from @emph{Waf} -and then the ``Compilation finished successfully'' message. The -next message, @code{UDP Echo Simulation} is from the running program. When -it ran, the program will have created a file named @code{tutorial.tr}. -Because of the way that Waf works, the file is not created in the local -directory, it is created at the top-level directory of the repository. So, -change into the top level directory and take a look at the file -@code{tutorial.tr} in your favorite editor. - -@subsubsection Parsing Ascii Traces -@cindex parsing ascii traces - -This section parses in detail the structure of the ascii tracing -output. If you find this output format self explanatory (it -resembles tcpdump output), you may skip to the next -section on pcap tracing. - -@cindex trace event -There's a lot of information there in a pretty dense form, but the first thing -to notice is that there are a number of distinct lines in this file. It may -be difficult to see this clearly unless you widen your windows considerably. -Each line in the file corresponds to a @emph{trace event}. A trace event -happens whenever specific conditions happen in the simulation. In this case -we are tracing events on the @emph{device queue} present in every net device -on every node in the simulation. The device queue is a queue through which -every packet destined for a channel must pass --- it is the device -@emph{transmit} queue. Note that each line in the trace file begins with a -lone character (has a space after it). This character will have the following -meaning: - -@cindex enqueue -@cindex dequeue -@cindex drop -@itemize @bullet -@item @code{+}: An enqueue operation occurred on the device queue; -@item @code{-}: A dequeue operation occurred on the device queue; -@item @code{d}: A packet was dropped, typically because the queue was full. -@end itemize - -Let's take a more detailed view of the first line. I'll break it down into -sections (indented for clarity) with a two digit reference number on the -left side: - -@verbatim - 00 + - 01 2 - 02 nodeid=0 - 03 device=0 - 04 queue-enqueue - 05 pkt-uid=9 - 06 ETHERNET - 07 length/type=0x806, - 08 source=08:00:2e:00:00:00, - 09 destination=ff:ff:ff:ff:ff:ff - 10 ARP(request - 11 source mac: 08:00:2e:00:00:00 - 12 source ipv4: 10.1.1.1 - 13 dest ipv4: 10.1.1.2) - 14 ETHERNET fcs=0 -@end verbatim - -@cindex trace event -@cindex simulation time -The first line of this expanded trace event (reference number 00) is the -queue operation. We have a @code{+} character, so this corresponds to an -@emph{enqueue} operation. The second line (reference 01) is the simulation -time expressed in seconds. You may recall that we asked the -@code{UdpEchoClient} to start sending packets at two seconds. Here we see -confirmation that this is, indeed, happening. - -@cindex node number -@cindex net device number -@cindex smart pointer -The next lines of the example listing (references 02 and 03) tell us that -this trace event originated in a given node and net device. Each time a node -is created it is given an identifying number that monotonically increases from -zero. Therefore, @code{nodeid=0} means that the node in which the given trace -event originated is the first node we created. In the case of our script, -this first node is is the node pointed to by the smart pointer @code{n0}. Not -too surprisingly, this is also the node to which we attached the -@code{UdpEchoClient}. The device number is local to each node, and so the -device given by @code{device=0} is the first net device that we added to the -node in question. In our simulation, this corresponds to the -@code{CsmaNetDevice} we added to node zero (@code{n0}). - -@cindex uid -@cindex unique ID -@cindex packet -The next line (reference 04) is a more readable form of the operation code -seen in the first line --- i.e., the character @code{+} means -@code{queue-enqueue}. Reference number 05 indicates that the @emph{unique id} -of the packet being enqueued is @code{9}. The fact that the first packet we -see has a unique ID of 9 should indicates to you that other things have -happened in the protocol stack before we got to this point. This will become -clear momentarily. - -@cindex Ethernet -@cindex MAC address -Reference items 06 and 14 indicate that this is an Ethernet packet with -a zero (not computed) checksum (note the indentation to make parsing this -trace event a little easier). Reference 08 and 09 are the source and -destination addresses of this packet. The packet is from the MAC address we -assigned to the node zero net device in the script, and is destined for the -broadcast address --- this is a broadcast packet. - -@cindex Address Resolution Protocol -@cindex ARP -@cindex ARP|request -Reference items 10 through 13 make clear what is happening. This is an ARP -(Address Resolution Protocol) request for the MAC address of the node on -which the @code{UdpEchoServer} resides. The protocol stack can't send a UDP -packet to be echoed until it knows (resolves) the MAC address; and this trace -event corresponds to an ARP request being queued for transmission to the local -network. The next line in the trace file (partially expanded), - -@verbatim - 00 - - 01 2 - 02 nodeid=0 - 03 device=0 - 04 queue-dequeue - 05 pkt-uid=9 - ... -@end verbatim - -shows the (same) ARP request packet being dequeued from the device queue by -the net device and (implicitly) being sent down the channel to the broadcast -MAC address. We are not tracing net device reception events so we don't -actually see all of the net devices receiving the broadcast packet. We do, -however see the following in the third line of the trace file: - -@verbatim - 00 + - 01 2.00207 - 02 nodeid=1 - 03 device=0 - 04 queue-enqueue - 05 pkt-uid=10 - 06 ETHERNET - 07 length/type=0x806, - 08 source=08:00:2e:00:00:01, - 09 destination=08:00:2e:00:00:00, - 10 ARP(reply - 11 source mac: 08:00:2e:00:00:01 - 12 source ipv4: 10.1.1.2 - 13 dest mac: 08:00:2e:00:00:00 - 14 dest ipv4: 10.1.1.1) - 15 ETHERNET fcs=0 -@end verbatim - -@cindex simulation time -@cindex ARP|response -Notice that this is a queue-enqueue operation (references 00 and 04) happening -on node one (reference 02) at simulation time 2.00207 seconds (reference 01). -Looking at the packet payload (references 10-14) we see that this is an ARP -reply to the request sent by node one. Note that the simulation time -(reference 01) is now 2.00207 seconds. This is direct result of the data rate -(5 mb/s) and latency (2 ms) parameters that we passed to the -@code{CsmaChannel} when we created it. Clearly the ARP request packet was -sent over the channel and received approximately 2 ms later by node one. A -corresponding ARP response packet was created and enqueued on node one's net -device. It is this enqueue trace event that has being logged. - -@cindex queue -@cindex queue|transmit -@cindex echo -Given the current state of affairs, the next thing you may expect to see is -this ARP request being received by node zero, but remember we are only looking -at trace events on the device @emph{transmit} queue. The reception of the ARP -response by node zero will not directly trigger any trace event in this case, -but it will enable the protocol stack to continue what it was originally doing -(trying to send an echo packet). Thus, the next line we see in the trace file -(@code{tutorial.tr}) is the first UDP echo packet being sent to the net device. - -@verbatim - 00 + - 01 2.00415 - 02 nodeid=0 - 03 device=0 - 04 queue-enqueue - 05 pkt-uid=7 - 06 ETHERNET - 07 length/type=0x800, - 08 source=08:00:2e:00:00:00, - 09 destination=08:00:2e:00:00:01 - 10 IPV4( - 11 tos 0x0 - 12 ttl 64 - 13 id 0 - 14 offset 0 - 15 flags [none] - 16 length: 1052) 10.1.1.1 > 10.1.1.2 - 17 UDP(length: 1032) - 18 49153 > 7 - 19 DATA (length 1024) - 20 ETHERNET fcs=0 -@end verbatim - -@cindex simulation time -@cindex echo -@cindex ARP -@cindex ARP|request -@cindex ARP|response -@cindex IP -@cindex Ipv4 -I won't go into too much detail about this packet, but I will point out a -few key items in the trace. First, the packet was enqueued at simulation time -of 2.00415 seconds. This time reflects the fact that the echo client -application started at 2. seconds and there were two ARP packets transmitted -across the network (two milliseconds + data transmission time each way). The -packet unique identifier (reference 05) is 7. Notice that this is a lower -number than the ARP request packet, which had a unique ID of 9. This tells -us that the UDP packet was actually created before the ARP request packet --- -which makes perfect sense since it was the attempt to send packet 7 that -triggered sending the ARP request packet 9. Note that this an Ethernet -packet (reference 06) like all other packets in this simulation, however this -particular packet carries an IPV4 payload and therefore has an IP version 4 -header (indicated by references 10-16). This Ipv4 in turn contains a UDP -header (references 17, 18) and finally 1024 bytes of data (reference 20). -Clearly, this is the UDP echo packet emitted by the -@code{UdpEchoClient Application}. - -The next trace event is an ARP request from node one. We can infer that node -one has received the UDP echo packet and the @code{UdpEchoServer Application} -on that node has turned the packet around. Just as node zero needed to ARP -for the MAC address of node one, now node one must ARP for the MAC address of -node zero. We see the ARP request enqueued on the transmit queue of node one; -then we see the ARP request dequeued from the transmit queue of node one (and -implicitly transmitted to node zero). Then we see an ARP response enqueued -on the transmit queue of node zero; and finally the ARP response dequeued (and -implicitly transmitted back to node one). - -This exchange is summarized in the following trace event excerpts, - -@verbatim - + 2.00786 nodeid=1 ... ARP(request ... - - 2.00786 nodeid=1 ... ARP(request ... - + 2.00994 nodeid=0 ... ARP(reply ... - - 2.00994 nodeid=0 ... ARP(reply ... -@end verbatim - -The final two trace events in the @code{tutorial.tr} file correspond to the -echoed packet being enqueued for transmission on the net device for node one, -and that packet being dequeued (and implicitly transmitted back to node zero). - -@cindex AsciiTrace!TraceAllNetDeviceRx -@cindex ARP!request -If you look at the trace file (@code{tutorial.tr}) you will also see some -entries with an @code{r} event, indicating a -@emph{receive} trace event. Recall that the first packet sent on the network -was a broadcast ARP request. We should then see all four nodes receive a -copy of this request. This is the case, as the first four receive trace -events are, - -@verbatim - r 2.00207 nodeid=0 device=0 dev-rx pkt-uid=9 ARP(request ... - r 2.00207 nodeid=1 device=0 dev-rx pkt-uid=9 ARP(request ... - r 2.00207 nodeid=2 device=0 dev-rx pkt-uid=9 ARP(request ... - r 2.00207 nodeid=3 device=0 dev-rx pkt-uid=9 ARP(request ... -@end verbatim - -@cindex unique ID -You can see that a copy of the broadcast packet with unique ID 9 was received -by the net devices on nodes 0, 1, 2 and 3. We leave it up to you to parse the -rest of the trace file and understand the remaining reception events. - -@subsection PCAP Trace Wrapper -@cindex pcap -@cindex Wireshark -The @command{ns-3} @emph{pcap trace wrapper} is used to create trace files in -@code{.pcap} format. The acronym pcap (usually written in lower case) stands -for @emph{p}acket @emph{cap}ture, and is actually an API that includes the -definition of a @code{.pcap} file format. The most popular program that can -read and display this format is Wireshark (formerly called Ethereal). -However, there are many traffic trace analyzers that use this packet -format, including X, Y, and Z. We encourage users to exploit the -many tools available for analyzing pcap traces; below, we show how -tcpdump and Wireshark can be used.. - -@cindex tutorial-csma-echo-ascii-trace.cc -@cindex tutorial-csma-echo-pcap-trace.cc -The code used to enable pcap tracing is similar to that for ASCII tracing. -We have provided another file, @code{tutorial-csma-echo-pcap-trace.cc} that -uses the pcap trace wrapper. We have added the code to include the pcap -trace wrapper definitions: - -@verbatim - #include "ns3/pcap-trace.h" -@end verbatim - -And then added the following code below the AsciiTrace methods: - -@cindex PcapTrace -@cindex PcapTrace!TraceAllIp -@verbatim - PcapTrace pcaptrace ("tutorial.pcap"); - pcaptrace.TraceAllIp (); -@end verbatim - -The first line of the code immediately above declares an object of type -@code{PcapTrace} named @code{pcaptrace} and passes a string parameter to its -constructor. This object is used to hide the details of the actual tracing -subsystem. The parameter is a base file name from which the actual trace file -names will be built. The second line of code tells the @code{PcamTrace} -object to trace all IP activity in all of the nodes present in the simulation. - -@cindex interface index -Trace files are not created until trace activity is detected. Each file name -is composed of the base file name, followed by a @code{'-'}, a node id followed -by a @code{'-}', and an IP interface index. You will soon see a file named -@code{tutorial.pcap-0-1}, for example. This will be the trace file generated -as events are detected on node zero, interface index one. N.B. Interface -indices are different that net device indices --- interface index zero -corresponds to the loopback interface and interface index one corresponds to -the first net device you added to a node. - -You may run the new program just like all of the others so far: - -@cindex Waf -@verbatim - ./waf --run tutorial-csma-echo-pcap-trace -@end verbatim - -If you look at the top level directory of your distribution, you should now -see three log files: @code{tutorial.tr} is the ASCII trace file we have -previously examined. @code{tutorial.pcap-0-1} and @code{tutorial.pcap-1-1} -are the new pcap files we just generated. There will not be files -corresponding to nodes two and three since we have not sent any IP packets to -those nodes. - -@subsubsection Reading output with tcpdump -@cindex tcpdump - -@subsubsection Reading output with Wireshark -@cindex Wireshark -If you are unfamiliar with Wireshark, there is a web site available from which -you can download programs and documentation: @uref{http://www.wireshark.org/}. - -If you have Wireshark available, you can open each of the trace files and -display the contents as if you had captured the packets using a -@emph{packet sniffer}. Note that only IP packets are traced using this -wrapper, so you will not see the ARP exchanges that were logged when using -the ASCII trace wrapper. You are encouraged to take a look at the contents -of these pcap files using your favorite pcap software (or Wireshark). - -@node Advanced Tracing -@section Advanced Tracing - diff -r c9133c87760d -r 7ff69b244b5b doc/tutorial/in-process/statistics.texi --- a/doc/tutorial/in-process/statistics.texi Sun Jan 02 22:57:04 2011 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,9 +0,0 @@ -@node Statistics -@chapter Statistics -@anchor{chap:Statistics} - -ns-3 does not presently have support for statistics (automatically generated -statistical output). This is planned -for development later in 2008. If you are interested in contributing, -please see @uref{http://www.nsnam.org/wiki/index.php/Suggested_Projects,,our suggested projects page} or contact the ns-developers -list. diff -r c9133c87760d -r 7ff69b244b5b doc/tutorial/in-process/troubleshoot.texi --- a/doc/tutorial/in-process/troubleshoot.texi Sun Jan 02 22:57:04 2011 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,82 +0,0 @@ -@node Troubleshooting -@chapter Troubleshooting - -This chapter posts some information about possibly common errors in building -or running ns-3 programs. - -Please note that the wiki (@uref{http://www.nsnam.org/wiki/index.php/Troubleshooting}) may have contributed items. - -@node Build errors -@section Build errors - -@node Run-time errors -@section Run-time errors - -Sometimes, errors can occur with a program after a successful build. These -are run-time errors, and can commonly occur when memory is corrupted or -pointer values are unexpectedly null. - -Here is an example of what might occur: - -@verbatim -ns-old:~/ns-3-nsc$ ./waf --run tcp-point-to-point -Entering directory `/home/tomh/ns-3-nsc/build' -Compilation finished successfully -Command ['/home/tomh/ns-3-nsc/build/debug/examples/tcp-point-to-point'] exited with code -11 -@end verbatim - -The error message says that the program terminated unsuccessfully, but it is -not clear from this information what might be wrong. To examine more -closely, try running it under the @uref{http://sources.redhat.com/gdb/,,gdb debugger}: - -@verbatim -ns-old:~/ns-3-nsc$ ./waf --run tcp-point-to-point --command-template="gdb %s" -Entering directory `/home/tomh/ns-3-nsc/build' -Compilation finished successfully -GNU gdb Red Hat Linux (6.3.0.0-1.134.fc5rh) -Copyright 2004 Free Software Foundation, Inc. -GDB is free software, covered by the GNU General Public License, and you are -welcome to change it and/or distribute copies of it under certain conditions. -Type "show copying" to see the conditions. -There is absolutely no warranty for GDB. Type "show warranty" for details. -This GDB was configured as "i386-redhat-linux-gnu"...Using host libthread_db library "/lib/libthread_db.so.1". - -(gdb) run -Starting program: /home/tomh/ns-3-nsc/build/debug/examples/tcp-point-to-point -Reading symbols from shared object read from target memory...done. -Loaded system supplied DSO at 0xf5c000 - -Program received signal SIGSEGV, Segmentation fault. -0x0804aa12 in main (argc=1, argv=0xbfdfefa4) - at ../examples/tcp-point-to-point.cc:136 -136 Ptr localSocket = socketFactory->CreateSocket (); -(gdb) p localSocket -$1 = {m_ptr = 0x3c5d65} -(gdb) p socketFactory -$2 = {m_ptr = 0x0} -(gdb) quit -The program is running. Exit anyway? (y or n) y -@end verbatim - -Note first the way the program was invoked-- pass the command to run as -an argument to the command template "gdb %s". - -This tells us that there was an attempt to dereference a null pointer -socketFactory. - -Let's look around line 136 of tcp-point-to-point, as gdb suggests: -@verbatim - Ptr socketFactory = n2->GetObject (Tcp::iid); - Ptr localSocket = socketFactory->CreateSocket (); - localSocket->Bind (); -@end verbatim - -The culprit here is that the return value of GetObject is not being -checked and may be null. - -Sometimes you may need to use the @uref{http://valgrind.org,,valgrind memory -checker} for more subtle errors. Again, you invoke the use of valgrind -similarly: -@verbatim -ns-old:~/ns-3-nsc$ ./waf --run tcp-point-to-point --command-template="valgrind %s" -@end verbatim diff -r c9133c87760d -r 7ff69b244b5b doc/tutorial/in-process/tutorial.css --- a/doc/tutorial/in-process/tutorial.css Sun Jan 02 22:57:04 2011 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,156 +0,0 @@ -body { - font-family: "Trebuchet MS", "Bitstream Vera Sans", verdana, lucida, arial, helvetica, sans-serif; - background: white; - color: black; - font-size: 11pt; -} - -h1, h2, h3, h4, h5, h6 { -# color: #990000; - color: #009999; -} - -pre { - font-size: 10pt; - background: #e0e0e0; - color: black; -} - -a:link, a:visited { - font-weight: normal; - text-decoration: none; - color: #0047b9; -} - -a:hover { - font-weight: normal; - text-decoration: underline; - color: #0047b9; -} - -img { - border: 0px; -} - -#main th { - font-size: 12pt; - background: #b0b0b0; -} - -.odd { - font-size: 12pt; - background: white; -} - -.even { - font-size: 12pt; - background: #e0e0e0; -} - -.answer { - font-size: large; - font-weight: bold; -} - -.answer p { - font-size: 12pt; - font-weight: normal; -} - -.answer ul { - font-size: 12pt; - font-weight: normal; -} - -#container { - position: absolute; - width: 100%; - height: 100%; - top: 0px; -} - -#feedback { - color: #b0b0b0; - font-size: 9pt; - font-style: italic; -} - -#header { - position: absolute; - margin: 0px; - top: 10px; - height:96px; - left: 175px; - right: 10em; - bottom: auto; - background: white; - clear: both; -} - -#middle { - position: absolute; - left: 0; - height: auto; - width: 100%; -} - -#main { - position: absolute; - top: 50px; - left: 175px; - right: 100px; - background: white; - padding: 0em 0em 0em 0em; -} - -#navbar { - position: absolute; - top: 75px; - left: 0em; - width: 146px; - padding: 0px; - margin: 0px; - font-size: 10pt; -} - -#navbar a:link, #navbar a:visited { - font-weight: normal; - text-decoration: none; - color: #0047b9; -} - -#navbar a:hover { - font-weight: normal; - text-decoration: underline; - color: #0047b9; -} - -#navbar dl { - width: 146px; - padding: 0; - margin: 0 0 10px 0px; - background: #99ffff url(images/box_bottom2.gif) no-repeat bottom left; -} - -#navbar dt { - padding: 6px 10px; - font-size: 100%; - font-weight: bold; - background: #009999; - margin: 0px; - border-bottom: 1px solid #fff; - color: white; - background: #009999 url(images/box_top2.gif) no-repeat top left; -} - -#navbar dd { - font-size: 100%; - margin: 0 0 0 0px; - padding: 6px 10px; - color: #0047b9; -} - -dd#selected { - background: #99ffff url(images/arrow.gif) no-repeat; - background-position: 4px 10px; -} diff -r c9133c87760d -r 7ff69b244b5b doc/tutorial/in-process/tutorial.texi --- a/doc/tutorial/in-process/tutorial.texi Sun Jan 02 22:57:04 2011 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,105 +0,0 @@ -\input texinfo @c -*-texinfo-*- -@c %**start of header -@setfilename ns-3.info -@settitle ns-3 tutorial -@c @setchapternewpage odd -@c %**end of header - -@ifinfo -Primary documentation for the @command{ns-3} project is available in -three forms: -@itemize @bullet -@item @uref{http://www.nsnam.org/doxygen/index.html,,ns-3 Doxygen/Manual}: Documentation of the public APIs of the simulator -@item Tutorial (this document) -@item @uref{http://www.nsnam.org/wiki/index.php,, ns-3 wiki} -@end itemize - -This document is written in GNU Texinfo and is to be maintained in -revision control on the @command{ns-3} code server. Both PDF and HTML versions -should be available on the server. Changes to -the document should be discussed on the ns-developers@@isi.edu mailing list. -@end ifinfo - -@copying - -This is an @command{ns-3} tutorial. -Primary documentation for the @command{ns-3} project is available in -three forms: -@itemize @bullet -@item @uref{http://www.nsnam.org/doxygen/index.html,,ns-3 Doxygen/Manual}: Documentation of the public APIs of the simulator -@item Tutorial (this document) -@item @uref{http://www.nsnam.org/wiki/index.php,, ns-3 wiki} -@end itemize - -This document is written in GNU Texinfo and is to be maintained in -revision control on the @command{ns-3} code server. Both PDF and HTML -versions should be available on the server. Changes to -the document should be discussed on the ns-developers@@isi.edu mailing list. - -This software is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This software 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, see @uref{http://www.gnu.org/licenses/}. -@end copying - -@titlepage -@title ns-3 Tutorial -@author ns-3 project -@author feedback: ns-developers@@isi.edu -@today{} - -@c @page -@vskip 0pt plus 1filll -@insertcopying -@end titlepage - -@c So the toc is printed at the start. -@anchor{Full Table of Contents} -@contents - -@ifnottex -@node Top, Overview, Full Table of Contents -@top ns-3 Tutorial (html version) - -For a pdf version of this tutorial, -see @uref{http://www.nsnam.org/docs/tutorial.pdf}. - -@insertcopying -@end ifnottex - -@menu -* Tutorial Goals:: -Part 1: Getting Started with ns-3 -* Overview:: -* Browsing:: -* Resources:: -* Downloading and Compiling:: -* Some-Prerequisites:: -Part 2: Reading ns-3 Programs -* A-First-ns-3-Script:: -Part 3: Reconfiguring Existing ns-3 Scripts -* Logging:: -* ns-3 Attributes:: -* Tracing:: -* Statistics:: -Part 4: Creating New or Revised Topologies -* Helper Functions:: -@end menu - -@include introduction.texi -@include log.texi -@include attributes.texi -@include statistics.texi -@include helpers.texi - -@printindex cp - -@bye diff -r c9133c87760d -r 7ff69b244b5b doc/tutorial/introduction.texi --- a/doc/tutorial/introduction.texi Sun Jan 02 22:57:04 2011 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,310 +0,0 @@ - -@c ======================================================================== -@c Begin document body here -@c ======================================================================== - -@c ======================================================================== -@c PART: Introduction -@c ======================================================================== -@c The below chapters are under the major heading "Introduction" -@c This is similar to the Latex \part command -@c -@c ======================================================================== -@c Introduction -@c ======================================================================== -@node Introduction -@chapter Introduction - -@menu -* For ns-2 Users:: -* Contributing:: -* Tutorial Organization:: -@end menu - -The @command{ns-3} simulator is a discrete-event network simulator targeted -primarily for research and educational use. The -@uref{http://www.nsnam.org,,ns-3 project}, -started in 2006, is an open-source project developing @command{ns-3}. - -Primary documentation for the @command{ns-3} project is available in four -forms: -@itemize @bullet -@item @uref{http://www.nsnam.org/doxygen/index.html,,ns-3 Doxygen/Manual}: -Documentation of the public APIs of the simulator -@item Tutorial (this document) -@item @uref{http://www.nsnam.org/docs/manual.html,,Reference Manual}: Reference Manual -@item @uref{http://www.nsnam.org/wiki/index.php,, ns-3 wiki} -@end itemize - -The purpose of this tutorial is to introduce new @command{ns-3} users to the -system in a structured way. It is sometimes difficult for new users to -glean essential information from detailed manuals and to convert this -information into working simulations. In this tutorial, we will build -several example simulations, introducing and explaining key concepts and -features as we go. - -As the tutorial unfolds, we will introduce the full @command{ns-3} documentation -and provide pointers to source code for those interested in delving deeper -into the workings of the system. - -A few key points are worth noting at the onset: -@itemize @bullet -@item Ns-3 is not an extension of @uref{http://www.isi.edu/nsnam/ns,,ns-2}; -it is a new simulator. The two simulators are both written in C++ but -@command{ns-3} is a new simulator that does not support the ns-2 APIs. Some -models from ns-2 have already been ported from ns-2 to @command{ns-3}. The -project will continue to maintain ns-2 while @command{ns-3} is being built, -and will study transition and integration mechanisms. -@item @command{Ns-3} is open-source, and the project strives to maintain an -open environment for researchers to contribute and share their software. -@end itemize - -@node For ns-2 Users -@section For ns-2 Users - -For those familiar with ns-2, the most visible outward change when moving to -@command{ns-3} is the choice of scripting language. Ns-2 is -scripted in OTcl and results of simulations can be visualized using the -Network Animator @command{nam}. It is not possible to run a simulation -in ns-2 purely from C++ (i.e., as a main() program without any OTcl). -Moreover, some components of ns-2 are written in C++ and others in OTcl. -In @command{ns-3}, the simulator is written entirely in C++, with optional -Python bindings. Simulation scripts can therefore be written in C++ -or in Python. The results of some simulations can be visualized by -@command{nam}, but new animators are under development. Since @command{ns-3} -generates pcap packet trace files, other utilities can be used to -analyze traces as well. -In this tutorial, we will first concentrate on scripting -directly in C++ and interpreting results via trace files. - -But there are similarities as well (both, for example, are based on C++ -objects, and some code from ns-2 has already been ported to @command{ns-3}). -We will try to highlight differences between ns-2 and @command{ns-3} -as we proceed in this tutorial. - -A question that we often hear is "Should I still use ns-2 or move to -@command{ns-3}?" The answer is that it depends. @command{ns-3} does not have -all of the models that ns-2 currently has, but on the other hand, @command{ns-3} -does have new capabilities (such as handling multiple interfaces on nodes -correctly, use of IP addressing and more alignment with Internet -protocols and designs, more detailed 802.11 models, etc.). ns-2 -models can usually be ported to @command{ns-3} (a porting guide is under -development). There is active development on multiple fronts for -@command{ns-3}. The @command{ns-3} developers believe (and certain early users -have proven) that @command{ns-3} is ready for active use, and should be an -attractive alternative for users looking to start new simulation projects. - -@node Contributing -@section Contributing - -@cindex contributing -@command{Ns-3} is a research and educational simulator, by and for the -research community. It will rely on the ongoing contributions of the -community to develop new models, debug or maintain existing ones, and share -results. There are a few policies that we hope will encourage people to -contribute to @command{ns-3} like they have for ns-2: -@itemize @bullet -@item Open source licensing based on GNU GPLv2 compatibility; -@item @uref{http://www.nsnam.org/wiki/index.php,,wiki}; -@item @uref{http://www.nsnam.org/wiki/index.php/Contributed_Code,,Contributed Code} page, similar to ns-2's popular -@uref{http://nsnam.isi.edu/nsnam/index.php/Contributed_Code,,Contributed Code} -page; -@item @code{src/contrib} directory (we will host your contributed code); -@item Open @uref{http://www.nsnam.org/bugzilla,,bug tracker}; -@item @command{Ns-3} developers will gladly help potential contributors to get -started with the simulator (please contact @uref{http://www.nsnam.org/people.html,,one of us}). -@end itemize - -We realize that if you are reading this document, contributing back to -the project is probably not your foremost concern at this point, but -we want you to be aware that contributing is in the spirit of the project and -that even the act of dropping us a note about your early experience -with @command{ns-3} (e.g. "this tutorial section was not clear..."), -reports of stale documentation, etc. are much appreciated. - -@node Tutorial Organization -@section Tutorial Organization - -The tutorial assumes that new users might initially follow a path such as the -following: - -@itemize @bullet -@item Try to download and build a copy; -@item Try to run a few sample programs; -@item Look at simulation output, and try to adjust it. -@end itemize - -As a result, we have tried to organize the tutorial along the above -broad sequences of events. - -@c ======================================================================== -@c Resources -@c ======================================================================== - -@node Resources -@chapter Resources - -@menu -* The Web:: -* Mercurial:: -* Waf:: -* Development Environment:: -* Socket Programming:: -@end menu - -@node The Web -@section The Web - -@cindex www.nsnam.org -@cindex documentation -@cindex architecture -There are several important resources of which any @command{ns-3} user must be -aware. The main web site is located at @uref{http://www.nsnam.org} and -provides access to basic information about the @command{ns-3} system. Detailed -documentation is available through the main web site at -@uref{http://www.nsnam.org/documents.html}. You can also find documents -relating to the system architecture from this page. - -There is a Wiki that complements the main @command{ns-3} web site which you will -find at @uref{http://www.nsnam.org/wiki/}. You will find user and developer -FAQs there, as well as troubleshooting guides, third-party contributed code, -papers, etc. - -@cindex mercurial repository -@cindex ns-3-dev repository -@cindex release repository -The source code may be found and browsed at @uref{http://code.nsnam.org/}. -There you will find the current development tree in the repository named -@code{ns-3-dev}. Past releases and experimental repositories of the core -developers may also be found there. - -@node Mercurial -@section Mercurial - -Complex software systems need some way to manage the organization and -changes to the underlying code and documentation. There are many ways to -perform this feat, and you may have heard of some of the systems that are -currently used to do this. The Concurrent Version System (CVS) is probably -the most well known. - -@cindex software configuration management -@cindex Mercurial -The @command{ns-3} project uses Mercurial as its source code management system. -Although you do not need to know much about Mercurial in order to complete -this tutorial, we recommend becoming familiar with Mercurial and using it -to access the source code. Mercurial has a web site at -@uref{http://www.selenic.com/mercurial/}, -from which you can get binary or source releases of this Software -Configuration Management (SCM) system. Selenic (the developer of Mercurial) -also provides a tutorial at -@uref{http://www.selenic.com/mercurial/wiki/index.cgi/Tutorial/}, -and a QuickStart guide at -@uref{http://www.selenic.com/mercurial/wiki/index.cgi/QuickStart/}. - -You can also find vital information about using Mercurial and @command{ns-3} -on the main @command{ns-3} web site. - -@node Waf -@section Waf - -@cindex Waf -@cindex make -@cindex build -Once you have source code downloaded to your local system, you will need -to compile that source to produce usable programs. Just as in the case of -source code management, there are many tools available to perform this -function. Probably the most well known of these tools is @code{make}. Along -with being the most well known, @code{make} is probably the most difficult to -use in a very large and highly configurable system. Because of this, many -alternatives have been developed. Recently these systems have been developed -using the Python language. - -The build system @code{Waf} is used on the @command{ns-3} project. It is one -of the new generation of Python-based build systems. You will not need to -understand any Python to build the existing @command{ns-3} system, and will -only have to understand a tiny and intuitively obvious subset of Python in -order to extend the system in most cases. - -For those interested in the gory details of Waf, the main web site can be -found at @uref{http://code.google.com/p/waf/}. - -@node Development Environment -@section Development Environment - -@cindex C++ -@cindex Python -As mentioned above, scripting in @command{ns-3} is done in C++ or Python. -As of ns-3.2, most of the @command{ns-3} API is available in Python, but the -models are written in C++ in either case. A working -knowledge of C++ and object-oriented concepts is assumed in this document. -We will take some time to review some of the more advanced concepts or -possibly unfamiliar language features, idioms and design patterns as they -appear. We don't want this tutorial to devolve into a C++ tutorial, though, -so we do expect a basic command of the language. There are an almost -unimaginable number of sources of information on C++ available on the web or -in print. - -If you are new to C++, you may want to find a tutorial- or cookbook-based -book or web site and work through at least the basic features of the language -before proceeding. For instance, -@uref{http://www.cplusplus.com/doc/tutorial/,,this tutorial}. - -@cindex toolchain -@cindex GNU -The @command{ns-3} system uses several components of the GNU ``toolchain'' -for development. A -software toolchain is the set of programming tools available in the given -environment. For a quick review of what is included in the GNU toolchain see, -@uref{http://en.wikipedia.org/wiki/GNU_toolchain}. @command{ns-3} uses gcc, -GNU binutils, and gdb. However, we do not use the GNU build system tools, -neither make nor autotools. We use Waf for these functions. - -@cindex Linux -Typically an @command{ns-3} author will work in Linux or a Linux-like -environment. For those running under Windows, there do exist environments -which simulate the Linux environment to various degrees. The @command{ns-3} -project supports development in the Cygwin environment for -these users. See @uref{http://www.cygwin.com/} -for details on downloading (MinGW is presently not officially supported, -although some of the project maintainers to work with it). Cygwin provides -many of the popular Linux system commands. It can, however, sometimes be -problematic due to the way it actually does its emulation, and sometimes -interactions with other Windows software can cause problems. - -@cindex Cygwin -@cindex MinGW -If you do use Cygwin or MinGW; and use Logitech products, we will save you -quite a bit of heartburn right off the bat and encourage you to take a look -at the @uref{http://oldwiki.mingw.org/index.php/FAQ,,MinGW FAQ}. - -@cindex Logitech -Search for ``Logitech'' and read the FAQ entry, ``why does make often -crash creating a sh.exe.stackdump file when I try to compile my source code.'' -Believe it or not, the @code{Logitech Process Monitor} insinuates itself into -every DLL in the system when it is running. It can cause your Cygwin or -MinGW DLLs to die in mysterious ways and often prevents debuggers from -running. Beware of Logitech software when using Cygwin. - -Another alternative to Cygwin is to install a virtual machine environment -such as VMware server and install a Linux virtual machine. - -@node Socket Programming -@section Socket Programming - -@cindex sockets -We will assume a basic facility with the Berkeley Sockets API in the examples -used in this tutorial. If you are new to sockets, we recommend reviewing the -API and some common usage cases. For a good overview of programming TCP/IP -sockets we recommend @uref{http://www.elsevier.com/wps/find/bookdescription.cws_home/717656/description#description,,TCP/IP Sockets in C, Donahoo and Calvert}. - -There is an associated web site that includes source for the examples in the -book, which you can find at: -@uref{http://cs.baylor.edu/~donahoo/practical/CSockets/}. - -If you understand the first four chapters of the book (or for those who do -not have access to a copy of the book, the echo clients and servers shown in -the website above) you will be in good shape to understand the tutorial. -There is a similar book on Multicast Sockets, -@uref{http://www.elsevier.com/wps/find/bookdescription.cws_home/700736/description#description,,Multicast Sockets, Makofske and Almeroth}. -that covers material you may need to understand if you look at the multicast -examples in the distribution. diff -r c9133c87760d -r 7ff69b244b5b doc/tutorial/pickle-to-xml.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/tutorial/pickle-to-xml.py Sun Jan 02 22:57:32 2011 -0800 @@ -0,0 +1,42 @@ +#!/usr/bin/python + + +# output xml format: +# +# zzzlllfile.frag +# ... +# + +import pickle +import os +import codecs + +def dump_pickles(out, dirname, filename, path): + f = open(os.path.join(dirname, filename), 'r') + data = pickle.load(f) + fragment_file = codecs.open(data['current_page_name'] + '.frag', mode='w', encoding='utf-8') + fragment_file.write(data['body']) + fragment_file.close() + out.write(' \n' % path) + out.write(' %s.frag\n' % data['current_page_name']) + if data['prev'] is not None: + out.write(' %s\n' % + (os.path.normpath(os.path.join(path, data['prev']['link'])), + data['prev']['title'])) + if data['next'] is not None: + out.write(' %s\n' % + (os.path.normpath(os.path.join(path, data['next']['link'])), + data['next']['title'])) + out.write(' \n') + f.close() + if data['next'] is not None: + next_path = os.path.normpath(os.path.join(path, data['next']['link'])) + next_filename = os.path.basename(next_path) + '.fpickle' + dump_pickles(out, dirname, next_filename, next_path) + return + +import sys + +sys.stdout.write('\n') +dump_pickles(sys.stdout, os.path.dirname(sys.argv[1]), os.path.basename(sys.argv[1]), '/') +sys.stdout.write('') diff -r c9133c87760d -r 7ff69b244b5b doc/tutorial/source/building-topologies.rst --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/tutorial/source/building-topologies.rst Sun Jan 02 22:57:32 2011 -0800 @@ -0,0 +1,1429 @@ +.. include:: replace.txt + + +Building Topologies +------------------- + +Building a Bus Network Topology +******************************* + +In this section we are going to expand our mastery of |ns3| network +devices and channels to cover an example of a bus network. |ns3| +provides a net device and channel we call CSMA (Carrier Sense Multiple Access). + +The |ns3| CSMA device models a simple network in the spirit of +Ethernet. A real Ethernet uses CSMA/CD (Carrier Sense Multiple Access with +Collision Detection) scheme with exponentially increasing backoff to contend +for the shared transmission medium. The |ns3| CSMA device and +channel models only a subset of this. + +Just as we have seen point-to-point topology helper objects when constructing +point-to-point topologies, we will see equivalent CSMA topology helpers in +this section. The appearance and operation of these helpers should look +quite familiar to you. + +We provide an example script in our examples/tutorial} directory. This script +builds on the ``first.cc`` script and adds a CSMA network to the +point-to-point simulation we've already considered. Go ahead and open +``examples/tutorial/second.cc`` in your favorite editor. You will have already seen +enough |ns3| code to understand most of what is going on in this +example, but we will go over the entire script and examine some of the output. + +Just as in the ``first.cc`` example (and in all ns-3 examples) the file +begins with an emacs mode line and some GPL boilerplate. + +The actual code begins by loading module include files just as was done in the +``first.cc`` example. + +:: + + #include "ns3/core-module.h" + #include "ns3/simulator-module.h" + #include "ns3/node-module.h" + #include "ns3/helper-module.h" + +One thing that can be surprisingly useful is a small bit of ASCII art that +shows a cartoon of the network topology constructed in the example. You will +find a similar "drawing" in most of our examples. + +In this case, you can see that we are going to extend our point-to-point +example (the link between the nodes n0 and n1 below) by hanging a bus network +off of the right side. Notice that this is the default network topology +since you can actually vary the number of nodes created on the LAN. If you +set nCsma to one, there will be a total of two nodes on the LAN (CSMA +channel) --- one required node and one "extra" node. By default there are +three "extra" nodes as seen below: + +:: + +// Default Network Topology +// +// 10.1.1.0 +// n0 -------------- n1 n2 n3 n4 +// point-to-point | | | | +// ================ +// LAN 10.1.2.0 + +Then the ns-3 namespace is ``used`` and a logging component is defined. +This is all just as it was in ``first.cc``, so there is nothing new yet. + +:: + + using namespace ns3; + + NS_LOG_COMPONENT_DEFINE ("SecondScriptExample"); + +The main program begins with a slightly different twist. We use a verbose +flag to determine whether or not the ``UdpEchoClientApplication`` and +``UdpEchoServerApplication`` logging components are enabled. This flag +defaults to true (the logging components are enabled) but allows us to turn +off logging during regression testing of this example. + +You will see some familiar code that will allow you to change the number +of devices on the CSMA network via command line argument. We did something +similar when we allowed the number of packets sent to be changed in the section +on command line arguments. The last line makes sure you have at least one +"extra" node. + +The code consists of variations of previously covered API so you should be +entirely comfortable with the following code at this point in the tutorial. + +:: + + bool verbose = true; + uint32_t nCsma = 3; + + CommandLine cmd; + cmd.AddValue ("nCsma", "Number of \"extra\" CSMA nodes/devices", nCsma); + cmd.AddValue ("verbose", "Tell echo applications to log if true", verbose); + + cmd.Parse (argc,argv); + + if (verbose) + { + LogComponentEnable("UdpEchoClientApplication", LOG_LEVEL_INFO); + LogComponentEnable("UdpEchoServerApplication", LOG_LEVEL_INFO); + } + + nCsma = nCsma == 0 ? 1 : nCsma; + +The next step is to create two nodes that we will connect via the +point-to-point link. The ``NodeContainer`` is used to do this just as was +done in ``first.cc``. + +:: + + NodeContainer p2pNodes; + p2pNodes.Create (2); + +Next, we declare another ``NodeContainer`` to hold the nodes that will be +part of the bus (CSMA) network. First, we just instantiate the container +object itself. + +:: + + NodeContainer csmaNodes; + csmaNodes.Add (p2pNodes.Get (1)); + csmaNodes.Create (nCsma); + +The next line of code ``Gets`` the first node (as in having an index of one) +from the point-to-point node container and adds it to the container of nodes +that will get CSMA devices. The node in question is going to end up with a +point-to-point device *and* a CSMA device. We then create a number of +"extra" nodes that compose the remainder of the CSMA network. Since we +already have one node in the CSMA network -- the one that will have both a +point-to-point and CSMA net device, the number of "extra" nodes means the +number nodes you desire in the CSMA section minus one. + +The next bit of code should be quite familiar by now. We instantiate a +``PointToPointHelper`` and set the associated default ``Attributes`` so +that we create a five megabit per second transmitter on devices created using +the helper and a two millisecond delay on channels created by the helper. + +:: + + PointToPointHelper pointToPoint; + pointToPoint.SetDeviceAttribute ("DataRate", StringValue ("5Mbps")); + pointToPoint.SetChannelAttribute ("Delay", StringValue ("2ms")); + + NetDeviceContainer p2pDevices; + p2pDevices = pointToPoint.Install (p2pNodes); + +We then instantiate a ``NetDeviceContainer`` to keep track of the +point-to-point net devices and we ``Install`` devices on the +point-to-point nodes. + +We mentioned above that you were going to see a helper for CSMA devices and +channels, and the next lines introduce them. The ``CsmaHelper`` works just +like a ``PointToPointHelper``, but it creates and connects CSMA devices and +channels. In the case of a CSMA device and channel pair, notice that the data +rate is specified by a *channel* ``Attribute`` instead of a device +``Attribute``. This is because a real CSMA network does not allow one to mix, +for example, 10Base-T and 100Base-T devices on a given channel. We first set +the data rate to 100 megabits per second, and then set the speed-of-light delay +of the channel to 6560 nano-seconds (arbitrarily chosen as 1 nanosecond per foot +over a 100 meter segment). Notice that you can set an ``Attribute`` using +its native data type. + +:: + + CsmaHelper csma; + csma.SetChannelAttribute ("DataRate", StringValue ("100Mbps")); + csma.SetChannelAttribute ("Delay", TimeValue (NanoSeconds (6560))); + + NetDeviceContainer csmaDevices; + csmaDevices = csma.Install (csmaNodes); + +Just as we created a ``NetDeviceContainer`` to hold the devices created by +the ``PointToPointHelper`` we create a ``NetDeviceContainer`` to hold +the devices created by our ``CsmaHelper``. We call the ``Install`` +method of the ``CsmaHelper`` to install the devices into the nodes of the +``csmaNodes NodeContainer``. + +We now have our nodes, devices and channels created, but we have no protocol +stacks present. Just as in the ``first.cc`` script, we will use the +``InternetStackHelper`` to install these stacks. + +:: + + InternetStackHelper stack; + stack.Install (p2pNodes.Get (0)); + stack.Install (csmaNodes); + +Recall that we took one of the nodes from the ``p2pNodes`` container and +added it to the ``csmaNodes`` container. Thus we only need to install +the stacks on the remaining ``p2pNodes`` node, and all of the nodes in the +``csmaNodes`` container to cover all of the nodes in the simulation. + +Just as in the ``first.cc`` example script, we are going to use the +``Ipv4AddressHelper`` to assign IP addresses to our device interfaces. +First we use the network 10.1.1.0 to create the two addresses needed for our +two point-to-point devices. + +:: + + Ipv4AddressHelper address; + address.SetBase ("10.1.1.0", "255.255.255.0"); + Ipv4InterfaceContainer p2pInterfaces; + p2pInterfaces = address.Assign (p2pDevices); + +Recall that we save the created interfaces in a container to make it easy to +pull out addressing information later for use in setting up the applications. + +We now need to assign IP addresses to our CSMA device interfaces. The +operation works just as it did for the point-to-point case, except we now +are performing the operation on a container that has a variable number of +CSMA devices --- remember we made the number of CSMA devices changeable by +command line argument. The CSMA devices will be associated with IP addresses +from network number 10.1.2.0 in this case, as seen below. + +:: + + address.SetBase ("10.1.2.0", "255.255.255.0"); + Ipv4InterfaceContainer csmaInterfaces; + csmaInterfaces = address.Assign (csmaDevices); + +Now we have a topology built, but we need applications. This section is +going to be fundamentally similar to the applications section of +``first.cc`` but we are going to instantiate the server on one of the +nodes that has a CSMA device and the client on the node having only a +point-to-point device. + +First, we set up the echo server. We create a ``UdpEchoServerHelper`` and +provide a required ``Attribute`` value to the constructor which is the server +port number. Recall that this port can be changed later using the +``SetAttribute`` method if desired, but we require it to be provided to +the constructor. + +:: + + UdpEchoServerHelper echoServer (9); + + ApplicationContainer serverApps = echoServer.Install (csmaNodes.Get (nCsma)); + serverApps.Start (Seconds (1.0)); + serverApps.Stop (Seconds (10.0)); + +Recall that the ``csmaNodes NodeContainer`` contains one of the +nodes created for the point-to-point network and ``nCsma`` "extra" nodes. +What we want to get at is the last of the "extra" nodes. The zeroth entry of +the ``csmaNodes`` container will be the point-to-point node. The easy +way to think of this, then, is if we create one "extra" CSMA node, then it +will be at index one of the ``csmaNodes`` container. By induction, +if we create ``nCsma`` "extra" nodes the last one will be at index +``nCsma``. You see this exhibited in the ``Get`` of the first line of +code. + +The client application is set up exactly as we did in the ``first.cc`` +example script. Again, we provide required ``Attributes`` to the +``UdpEchoClientHelper`` in the constructor (in this case the remote address +and port). We tell the client to send packets to the server we just installed +on the last of the "extra" CSMA nodes. We install the client on the +leftmost point-to-point node seen in the topology illustration. + +:: + + UdpEchoClientHelper echoClient (csmaInterfaces.GetAddress (nCsma), 9); + echoClient.SetAttribute ("MaxPackets", UintegerValue (1)); + echoClient.SetAttribute ("Interval", TimeValue (Seconds (1.))); + echoClient.SetAttribute ("PacketSize", UintegerValue (1024)); + + ApplicationContainer clientApps = echoClient.Install (p2pNodes.Get (0)); + clientApps.Start (Seconds (2.0)); + clientApps.Stop (Seconds (10.0)); + +Since we have actually built an internetwork here, we need some form of +internetwork routing. |ns3| provides what we call global routing to +help you out. Global routing takes advantage of the fact that the entire +internetwork is accessible in the simulation and runs through the all of the +nodes created for the simulation --- it does the hard work of setting up routing +for you without having to configure routers. + +Basically, what happens is that each node behaves as if it were an OSPF router +that communicates instantly and magically with all other routers behind the +scenes. Each node generates link advertisements and communicates them +directly to a global route manager which uses this global information to +construct the routing tables for each node. Setting up this form of routing +is a one-liner: + +:: + + Ipv4GlobalRoutingHelper::PopulateRoutingTables (); + +Next we enable pcap tracing. The first line of code to enable pcap tracing +in the point-to-point helper should be familiar to you by now. The second +line enables pcap tracing in the CSMA helper and there is an extra parameter +you haven't encountered yet. + +:: + + pointToPoint.EnablePcapAll ("second"); + csma.EnablePcap ("second", csmaDevices.Get (1), true); + +The CSMA network is a multi-point-to-point network. This means that there +can (and are in this case) multiple endpoints on a shared medium. Each of +these endpoints has a net device associated with it. There are two basic +alternatives to gathering trace information from such a network. One way +is to create a trace file for each net device and store only the packets +that are emitted or consumed by that net device. Another way is to pick +one of the devices and place it in promiscuous mode. That single device +then "sniffs" the network for all packets and stores them in a single +pcap file. This is how ``tcpdump``, for example, works. That final +parameter tells the CSMA helper whether or not to arrange to capture +packets in promiscuous mode. + +In this example, we are going to select one of the devices on the CSMA +network and ask it to perform a promiscuous sniff of the network, thereby +emulating what ``tcpdump`` would do. If you were on a Linux machine +you might do something like ``tcpdump -i eth0`` to get the trace. +In this case, we specify the device using ``csmaDevices.Get(1)``, +which selects the first device in the container. Setting the final +parameter to true enables promiscuous captures. + +The last section of code just runs and cleans up the simulation just like +the ``first.cc`` example. + +:: + + Simulator::Run (); + Simulator::Destroy (); + return 0; + } + +In order to run this example, copy the ``second.cc`` example script into +the scratch directory and use waf to build just as you did with +the ``first.cc`` example. If you are in the top-level directory of the +repository you just type, + +:: + + cp examples/tutorial/second.cc scratch/mysecond.cc + ./waf + +Warning: We use the file ``second.cc`` as one of our regression tests to +verify that it works exactly as we think it should in order to make your +tutorial experience a positive one. This means that an executable named +``second`` already exists in the project. To avoid any confusion +about what you are executing, please do the renaming to ``mysecond.cc`` +suggested above. + +If you are following the tutorial religiously (you are, aren't you) you will +still have the NS_LOG variable set, so go ahead and clear that variable and +run the program. + +:: + + export NS_LOG= + ./waf --run scratch/mysecond + +Since we have set up the UDP echo applications to log just as we did in +``first.cc``, you will see similar output when you run the script. + +:: + + Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' + Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' + 'build' finished successfully (0.415s) + Sent 1024 bytes to 10.1.2.4 + Received 1024 bytes from 10.1.1.1 + Received 1024 bytes from 10.1.2.4 + +Recall that the first message, "``Sent 1024 bytes to 10.1.2.4``," is the +UDP echo client sending a packet to the server. In this case, the server +is on a different network (10.1.2.0). The second message, "``Received 1024 +bytes from 10.1.1.1``," is from the UDP echo server, generated when it receives +the echo packet. The final message, "``Received 1024 bytes from 10.1.2.4``," +is from the echo client, indicating that it has received its echo back from +the server. + +If you now go and look in the top level directory, you will find three trace +files: + +:: + + second-0-0.pcap second-1-0.pcap second-2-0.pcap + +Let's take a moment to look at the naming of these files. They all have the +same form, ``--.pcap``. For example, the first file +in the listing is ``second-0-0.pcap`` which is the pcap trace from node +zero, device zero. This is the point-to-point net device on node zero. The +file ``second-1-0.pcap`` is the pcap trace for device zero on node one, +also a point-to-point net device; and the file ``second-2-0.pcap`` is the +pcap trace for device zero on node two. + +If you refer back to the topology illustration at the start of the section, +you will see that node zero is the leftmost node of the point-to-point link +and node one is the node that has both a point-to-point device and a CSMA +device. You will see that node two is the first "extra" node on the CSMA +network and its device zero was selected as the device to capture the +promiscuous-mode trace. + +Now, let's follow the echo packet through the internetwork. First, do a +tcpdump of the trace file for the leftmost point-to-point node --- node zero. + +:: + + tcpdump -nn -tt -r second-0-0.pcap + +You should see the contents of the pcap file displayed: + +:: + + reading from file second-0-0.pcap, link-type PPP (PPP) + 2.000000 IP 10.1.1.1.49153 > 10.1.2.4.9: UDP, length 1024 + 2.007602 IP 10.1.2.4.9 > 10.1.1.1.49153: UDP, length 1024 + +The first line of the dump indicates that the link type is PPP (point-to-point) +which we expect. You then see the echo packet leaving node zero via the +device associated with IP address 10.1.1.1 headed for IP address +10.1.2.4 (the rightmost CSMA node). This packet will move over the +point-to-point link and be received by the point-to-point net device on node +one. Let's take a look: + +:: + + tcpdump -nn -tt -r second-1-0.pcap + +You should now see the pcap trace output of the other side of the point-to-point +link: + +:: + + reading from file second-1-0.pcap, link-type PPP (PPP) + 2.003686 IP 10.1.1.1.49153 > 10.1.2.4.9: UDP, length 1024 + 2.003915 IP 10.1.2.4.9 > 10.1.1.1.49153: UDP, length 1024 + +Here we see that the link type is also PPP as we would expect. You see the +packet from IP address 10.1.1.1 (that was sent at 2.000000 seconds) headed +toward IP address 10.1.2.4 appear on this interface. Now, internally to this +node, the packet will be forwarded to the CSMA interface and we should see it +pop out on that device headed for its ultimate destination. + +Remember that we selected node 2 as the promiscuous sniffer node for the CSMA +network so let's then look at second-2-0.pcap and see if its there. + +:: + + tcpdump -nn -tt -r second-2-0.pcap + +You should now see the promiscuous dump of node two, device zero: + +:: + + reading from file second-2-0.pcap, link-type EN10MB (Ethernet) + 2.003696 arp who-has 10.1.2.4 (ff:ff:ff:ff:ff:ff) tell 10.1.2.1 + 2.003707 arp reply 10.1.2.4 is-at 00:00:00:00:00:06 + 2.003801 IP 10.1.1.1.49153 > 10.1.2.4.9: UDP, length 1024 + 2.003811 arp who-has 10.1.2.1 (ff:ff:ff:ff:ff:ff) tell 10.1.2.4 + 2.003822 arp reply 10.1.2.1 is-at 00:00:00:00:00:03 + 2.003915 IP 10.1.2.4.9 > 10.1.1.1.49153: UDP, length 1024 + +As you can see, the link type is now "Ethernet". Something new has appeared, +though. The bus network needs ``ARP``, the Address Resolution Protocol. +Node one knows it needs to send the packet to IP address 10.1.2.4, but it +doesn't know the MAC address of the corresponding node. It broadcasts on the +CSMA network (ff:ff:ff:ff:ff:ff) asking for the device that has IP address +10.1.2.4. In this case, the rightmost node replies saying it is at MAC address +00:00:00:00:00:06. Note that node two is not directly involved in this +exchange, but is sniffing the network and reporting all of the traffic it sees. + +This exchange is seen in the following lines, + +:: + + 2.003696 arp who-has 10.1.2.4 (ff:ff:ff:ff:ff:ff) tell 10.1.2.1 + 2.003707 arp reply 10.1.2.4 is-at 00:00:00:00:00:06 + +Then node one, device one goes ahead and sends the echo packet to the UDP echo +server at IP address 10.1.2.4. + +:: + + 2.003801 IP 10.1.1.1.49153 > 10.1.2.4.9: UDP, length 1024 + +The server receives the echo request and turns the packet around trying to send +it back to the source. The server knows that this address is on another network +that it reaches via IP address 10.1.2.1. This is because we initialized global +routing and it has figured all of this out for us. But, the echo server node +doesn't know the MAC address of the first CSMA node, so it has to ARP for it +just like the first CSMA node had to do. + +:: + + 2.003811 arp who-has 10.1.2.1 (ff:ff:ff:ff:ff:ff) tell 10.1.2.4 + 2.003822 arp reply 10.1.2.1 is-at 00:00:00:00:00:03 + +The server then sends the echo back to the forwarding node. + +:: + + 2.003915 IP 10.1.2.4.9 > 10.1.1.1.49153: UDP, length 1024 + +Looking back at the rightmost node of the point-to-point link, + +:: + + tcpdump -nn -tt -r second-1-0.pcap + +You can now see the echoed packet coming back onto the point-to-point link as +the last line of the trace dump. + +:: + + reading from file second-1-0.pcap, link-type PPP (PPP) + 2.003686 IP 10.1.1.1.49153 > 10.1.2.4.9: UDP, length 1024 + 2.003915 IP 10.1.2.4.9 > 10.1.1.1.49153: UDP, length 1024 + +Lastly, you can look back at the node that originated the echo +:: + + tcpdump -nn -tt -r second-0-0.pcap + +and see that the echoed packet arrives back at the source at 2.007602 seconds, + +:: + + reading from file second-0-0.pcap, link-type PPP (PPP) + 2.000000 IP 10.1.1.1.49153 > 10.1.2.4.9: UDP, length 1024 + 2.007602 IP 10.1.2.4.9 > 10.1.1.1.49153: UDP, length 1024 + +Finally, recall that we added the ability to control the number of CSMA devices +in the simulation by command line argument. You can change this argument in +the same way as when we looked at changing the number of packets echoed in the +``first.cc`` example. Try running the program with the number of "extra" +devices set to four: + +:: + + ./waf --run "scratch/mysecond --nCsma=4" + +You should now see, + +:: + + Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' + Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' + 'build' finished successfully (0.405s) + Sent 1024 bytes to 10.1.2.5 + Received 1024 bytes from 10.1.1.1 + Received 1024 bytes from 10.1.2.5 + +Notice that the echo server has now been relocated to the last of the CSMA +nodes, which is 10.1.2.5 instead of the default case, 10.1.2.4. + +It is possible that you may not be satisfied with a trace file generated by +a bystander in the CSMA network. You may really want to get a trace from +a single device and you may not be interested in any other traffic on the +network. You can do this fairly easily. + +Let's take a look at ``scratch/mysecond.cc`` and add that code enabling us +to be more specific. ``ns-3`` helpers provide methods that take a node +number and device number as parameters. Go ahead and replace the +``EnablePcap`` calls with the calls below. + +:: + + pointToPoint.EnablePcap ("second", p2pNodes.Get (0)->GetId (), 0); + csma.EnablePcap ("second", csmaNodes.Get (nCsma)->GetId (), 0, false); + csma.EnablePcap ("second", csmaNodes.Get (nCsma-1)->GetId (), 0, false); + +We know that we want to create a pcap file with the base name "second" and +we also know that the device of interest in both cases is going to be zero, +so those parameters are not really interesting. + +In order to get the node number, you have two choices: first, nodes are +numbered in a monotonically increasing fashion starting from zero in the +order in which you created them. One way to get a node number is to figure +this number out "manually" by contemplating the order of node creation. +If you take a look at the network topology illustration at the beginning of +the file, we did this for you and you can see that the last CSMA node is +going to be node number ``nCsma + 1``. This approach can become +annoyingly difficult in larger simulations. + +An alternate way, which we use here, is to realize that the +``NodeContainers`` contain pointers to |ns3| ``Node`` Objects. +The ``Node`` Object has a method called ``GetId`` which will return that +node's ID, which is the node number we seek. Let's go take a look at the +Doxygen for the ``Node`` and locate that method, which is further down in +the |ns3| core code than we've seen so far; but sometimes you have to +search diligently for useful things. + +Go to the Doxygen documentation for your release (recall that you can find it +on the project web site). You can get to the ``Node`` documentation by +looking through at the "Classes" tab and scrolling down the "Class List" +until you find ``ns3::Node``. Select ``ns3::Node`` and you will be taken +to the documentation for the ``Node`` class. If you now scroll down to the +``GetId`` method and select it, you will be taken to the detailed +documentation for the method. Using the ``GetId`` method can make +determining node numbers much easier in complex topologies. + +Let's clear the old trace files out of the top-level directory to avoid confusion +about what is going on, + +:: + + rm *.pcap + rm *.tr + +If you build the new script and run the simulation setting ``nCsma`` to 100, + +:: + + ./waf --run "scratch/mysecond --nCsma=100" + +you will see the following output: + +:: + + Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' + Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' + 'build' finished successfully (0.407s) + Sent 1024 bytes to 10.1.2.101 + Received 1024 bytes from 10.1.1.1 + Received 1024 bytes from 10.1.2.101 + +Note that the echo server is now located at 10.1.2.101 which corresponds to +having 100 "extra" CSMA nodes with the echo server on the last one. If you +list the pcap files in the top level directory you will see, + +:: + + second-0-0.pcap second-100-0.pcap second-101-0.pcap + +The trace file ``second-0-0.pcap`` is the "leftmost" point-to-point device +which is the echo packet source. The file ``second-101-0.pcap`` corresponds +to the rightmost CSMA device which is where the echo server resides. You may +have noticed that the final parameter on the call to enable pcap tracing on the +echo server node was false. This means that the trace gathered on that node +was in non-promiscuous mode. + +To illustrate the difference between promiscuous and non-promiscuous traces, we +also requested a non-promiscuous trace for the next-to-last node. Go ahead and +take a look at the ``tcpdump`` for ``second-100-0.pcap``. + +:: + + tcpdump -nn -tt -r second-100-0.pcap + +You can now see that node 100 is really a bystander in the echo exchange. The +only packets that it receives are the ARP requests which are broadcast to the +entire CSMA network. + +:: + + reading from file second-100-0.pcap, link-type EN10MB (Ethernet) + 2.003696 arp who-has 10.1.2.101 (ff:ff:ff:ff:ff:ff) tell 10.1.2.1 + 2.003811 arp who-has 10.1.2.1 (ff:ff:ff:ff:ff:ff) tell 10.1.2.101 + +Now take a look at the ``tcpdump`` for ``second-101-0.pcap``. + +:: + + tcpdump -nn -tt -r second-101-0.pcap + +You can now see that node 101 is really the participant in the echo exchange. + +:: + + reading from file second-101-0.pcap, link-type EN10MB (Ethernet) + 2.003696 arp who-has 10.1.2.101 (ff:ff:ff:ff:ff:ff) tell 10.1.2.1 + 2.003696 arp reply 10.1.2.101 is-at 00:00:00:00:00:67 + 2.003801 IP 10.1.1.1.49153 > 10.1.2.101.9: UDP, length 1024 + 2.003801 arp who-has 10.1.2.1 (ff:ff:ff:ff:ff:ff) tell 10.1.2.101 + 2.003822 arp reply 10.1.2.1 is-at 00:00:00:00:00:03 + 2.003822 IP 10.1.2.101.9 > 10.1.1.1.49153: UDP, length 1024 + +Models, Attributes and Reality +****************************** + +This is a convenient place to make a small excursion and make an important +point. It may or may not be obvious to you, but whenever one is using a +simulation, it is important to understand exactly what is being modeled and +what is not. It is tempting, for example, to think of the CSMA devices +and channels used in the previous section as if they were real Ethernet +devices; and to expect a simulation result to directly reflect what will +happen in a real Ethernet. This is not the case. + +A model is, by definition, an abstraction of reality. It is ultimately the +responsibility of the simulation script author to determine the so-called +"range of accuracy" and "domain of applicability" of the simulation as +a whole, and therefore its constituent parts. + +In some cases, like ``Csma``, it can be fairly easy to determine what is +*not* modeled. By reading the model description (``csma.h``) you +can find that there is no collision detection in the CSMA model and decide +on how applicable its use will be in your simulation or what caveats you +may want to include with your results. In other cases, it can be quite easy +to configure behaviors that might not agree with any reality you can go out +and buy. It will prove worthwhile to spend some time investigating a few +such instances, and how easily you can swerve outside the bounds of reality +in your simulations. + +As you have seen, |ns3| provides ``Attributes`` which a user +can easily set to change model behavior. Consider two of the ``Attributes`` +of the ``CsmaNetDevice``: ``Mtu`` and ``EncapsulationMode``. +The ``Mtu`` attribute indicates the Maximum Transmission Unit to the +device. This is the size of the largest Protocol Data Unit (PDU) that the +device can send. + +The MTU defaults to 1500 bytes in the ``CsmaNetDevice``. This default +corresponds to a number found in RFC 894, "A Standard for the Transmission +of IP Datagrams over Ethernet Networks." The number is actually derived +from the maximum packet size for 10Base5 (full-spec Ethernet) networks -- +1518 bytes. If you subtract the DIX encapsulation overhead for Ethernet +packets (18 bytes) you will end up with a maximum possible data size (MTU) +of 1500 bytes. One can also find that the ``MTU`` for IEEE 802.3 networks +is 1492 bytes. This is because LLC/SNAP encapsulation adds an extra eight +bytes of overhead to the packet. In both cases, the underlying hardware can +only send 1518 bytes, but the data size is different. + +In order to set the encapsulation mode, the ``CsmaNetDevice`` provides +an ``Attribute`` called ``EncapsulationMode`` which can take on the +values ``Dix`` or ``Llc``. These correspond to Ethernet and LLC/SNAP +framing respectively. + +If one leaves the ``Mtu`` at 1500 bytes and changes the encapsulation mode +to ``Llc``, the result will be a network that encapsulates 1500 byte PDUs +with LLC/SNAP framing resulting in packets of 1526 bytes, which would be +illegal in many networks, since they can transmit a maximum of 1518 bytes per +packet. This would most likely result in a simulation that quite subtly does +not reflect the reality you might be expecting. + +Just to complicate the picture, there exist jumbo frames (1500 < MTU <= 9000 bytes) +and super-jumbo (MTU > 9000 bytes) frames that are not officially sanctioned +by IEEE but are available in some high-speed (Gigabit) networks and NICs. One +could leave the encapsulation mode set to ``Dix``, and set the ``Mtu`` +``Attribute`` on a ``CsmaNetDevice`` to 64000 bytes -- even though an +associated ``CsmaChannel DataRate`` was set at 10 megabits per second. +This would essentially model an Ethernet switch made out of vampire-tapped +1980s-style 10Base5 networks that support super-jumbo datagrams. This is +certainly not something that was ever made, nor is likely to ever be made, +but it is quite easy for you to configure. + +In the previous example, you used the command line to create a simulation that +had 100 ``Csma`` nodes. You could have just as easily created a simulation +with 500 nodes. If you were actually modeling that 10Base5 vampire-tap network, +the maximum length of a full-spec Ethernet cable is 500 meters, with a minimum +tap spacing of 2.5 meters. That means there could only be 200 taps on a +real network. You could have quite easily built an illegal network in that +way as well. This may or may not result in a meaningful simulation depending +on what you are trying to model. + +Similar situations can occur in many places in |ns3| and in any +simulator. For example, you may be able to position nodes in such a way that +they occupy the same space at the same time, or you may be able to configure +amplifiers or noise levels that violate the basic laws of physics. + +|ns3| generally favors flexibility, and many models will allow freely +setting ``Attributes`` without trying to enforce any arbitrary consistency +or particular underlying spec. + +The thing to take home from this is that |ns3| is going to provide a +super-flexible base for you to experiment with. It is up to you to understand +what you are asking the system to do and to make sure that the simulations you +create have some meaning and some connection with a reality defined by you. + +Building a Wireless Network Topology +************************************ + +In this section we are going to further expand our knowledge of |ns3| +network devices and channels to cover an example of a wireless network. +|ns3| provides a set of 802.11 models that attempt to provide an +accurate MAC-level implementation of the 802.11 specification and a +"not-so-slow" PHY-level model of the 802.11a specification. + +Just as we have seen both point-to-point and CSMA topology helper objects when +constructing point-to-point topologies, we will see equivalent ``Wifi`` +topology helpers in this section. The appearance and operation of these +helpers should look quite familiar to you. + +We provide an example script in our ``examples/tutorial`` directory. This script +builds on the ``second.cc`` script and adds a Wifi network. Go ahead and +open ``examples/tutorial/third.cc`` in your favorite editor. You will have already +seen enough |ns3| code to understand most of what is going on in +this example, but there are a few new things, so we will go over the entire +script and examine some of the output. + +Just as in the ``second.cc`` example (and in all |ns3| examples) +the file begins with an emacs mode line and some GPL boilerplate. + +Take a look at the ASCII art (reproduced below) that shows the default network +topology constructed in the example. You can see that we are going to +further extend our example by hanging a wireless network off of the left side. +Notice that this is a default network topology since you can actually vary the +number of nodes created on the wired and wireless networks. Just as in the +``second.cc`` script case, if you change ``nCsma``, it will give you a +number of "extra" CSMA nodes. Similarly, you can set ``nWifi`` to +control how many ``STA`` (station) nodes are created in the simulation. +There will always be one ``AP`` (access point) node on the wireless +network. By default there are three "extra" CSMA nodes and three wireless +``STA`` nodes. + +The code begins by loading module include files just as was done in the +``second.cc`` example. There are a couple of new includes corresponding +to the Wifi module and the mobility module which we will discuss below. + +:: + +#include "ns3/core-module.h" +#include "ns3/simulator-module.h" +#include "ns3/node-module.h" +#include "ns3/helper-module.h" +#include "ns3/wifi-module.h" +#include "ns3/mobility-module.h" + +The network topology illustration follows: + +:: + + // Default Network Topology + // + // Wifi 10.1.3.0 + // AP + // * * * * + // | | | | 10.1.1.0 + // n5 n6 n7 n0 -------------- n1 n2 n3 n4 + // point-to-point | | | | + // ================ + // LAN 10.1.2.0 + +You can see that we are adding a new network device to the node on the left +side of the point-to-point link that becomes the access point for the wireless +network. A number of wireless STA nodes are created to fill out the new +10.1.3.0 network as shown on the left side of the illustration. + +After the illustration, the ``ns-3`` namespace is ``used`` and a logging +component is defined. This should all be quite familiar by now. + +:: + + using namespace ns3; + + NS_LOG_COMPONENT_DEFINE ("ThirdScriptExample"); + +The main program begins just like ``second.cc`` by adding some command line +parameters for enabling or disabling logging components and for changing the +number of devices created. + +:: + + bool verbose = true; + uint32_t nCsma = 3; + uint32_t nWifi = 3; + + CommandLine cmd; + cmd.AddValue ("nCsma", "Number of \"extra\" CSMA nodes/devices", nCsma); + cmd.AddValue ("nWifi", "Number of wifi STA devices", nWifi); + cmd.AddValue ("verbose", "Tell echo applications to log if true", verbose); + + cmd.Parse (argc,argv); + + if (verbose) + { + LogComponentEnable("UdpEchoClientApplication", LOG_LEVEL_INFO); + LogComponentEnable("UdpEchoServerApplication", LOG_LEVEL_INFO); + } + +Just as in all of the previous examples, the next step is to create two nodes +that we will connect via the point-to-point link. + +:: + + NodeContainer p2pNodes; + p2pNodes.Create (2); + +Next, we see an old friend. We instantiate a ``PointToPointHelper`` and +set the associated default ``Attributes`` so that we create a five megabit +per second transmitter on devices created using the helper and a two millisecond +delay on channels created by the helper. We then ``Intall`` the devices +on the nodes and the channel between them. + +:: + + PointToPointHelper pointToPoint; + pointToPoint.SetDeviceAttribute ("DataRate", StringValue ("5Mbps")); + pointToPoint.SetChannelAttribute ("Delay", StringValue ("2ms")); + + NetDeviceContainer p2pDevices; + p2pDevices = pointToPoint.Install (p2pNodes); + +Next, we declare another ``NodeContainer`` to hold the nodes that will be +part of the bus (CSMA) network. + +:: + + NodeContainer csmaNodes; + csmaNodes.Add (p2pNodes.Get (1)); + csmaNodes.Create (nCsma); + +The next line of code ``Gets`` the first node (as in having an index of one) +from the point-to-point node container and adds it to the container of nodes +that will get CSMA devices. The node in question is going to end up with a +point-to-point device and a CSMA device. We then create a number of "extra" +nodes that compose the remainder of the CSMA network. + +We then instantiate a ``CsmaHelper`` and set its ``Attributes`` as we did +in the previous example. We create a ``NetDeviceContainer`` to keep track of +the created CSMA net devices and then we ``Install`` CSMA devices on the +selected nodes. + +:: + + CsmaHelper csma; + csma.SetChannelAttribute ("DataRate", StringValue ("100Mbps")); + csma.SetChannelAttribute ("Delay", TimeValue (NanoSeconds (6560))); + + NetDeviceContainer csmaDevices; + csmaDevices = csma.Install (csmaNodes); + +Next, we are going to create the nodes that will be part of the Wifi network. +We are going to create a number of "station" nodes as specified by the +command line argument, and we are going to use the "leftmost" node of the +point-to-point link as the node for the access point. + +:: + + NodeContainer wifiStaNodes; + wifiStaNodes.Create (nWifi); + NodeContainer wifiApNode = p2pNodes.Get (0); + +The next bit of code constructs the wifi devices and the interconnection +channel between these wifi nodes. First, we configure the PHY and channel +helpers: + +:: + + YansWifiChannelHelper channel = YansWifiChannelHelper::Default (); + YansWifiPhyHelper phy = YansWifiPhyHelper::Default (); + +For simplicity, this code uses the default PHY layer configuration and +channel models which are documented in the API doxygen documentation for +the ``YansWifiChannelHelper::Default`` and ``YansWifiPhyHelper::Default`` +methods. Once these objects are created, we create a channel object +and associate it to our PHY layer object manager to make sure +that all the PHY layer objects created by the ``YansWifiPhyHelper`` +share the same underlying channel, that is, they share the same +wireless medium and can communication and interfere: + +:: + + phy.SetChannel (channel.Create ()); + +Once the PHY helper is configured, we can focus on the MAC layer. Here we choose to +work with non-Qos MACs so we use a NqosWifiMacHelper object to set MAC parameters. + +:: + + WifiHelper wifi = WifiHelper::Default (); + wifi.SetRemoteStationManager ("ns3::AarfWifiManager"); + + NqosWifiMacHelper mac = NqosWifiMacHelper::Default (); + +The ``SetRemoteStationManager`` method tells the helper the type of +rate control algorithm to use. Here, it is asking the helper to use the AARF +algorithm --- details are, of course, available in Doxygen. + +Next, we configure the type of MAC, the SSID of the infrastructure network we +want to setup and make sure that our stations don't perform active probing: + +:: + + Ssid ssid = Ssid ("ns-3-ssid"); + mac.SetType ("ns3::StaWifiMac", + "Ssid", SsidValue (ssid), + "ActiveProbing", BooleanValue (false)); + +This code first creates an 802.11 service set identifier (SSID) object +that will be used to set the value of the "Ssid" ``Attribute`` of +the MAC layer implementation. The particular kind of MAC layer that +will be created by the helper is specified by ``Attribute`` as +being of the "ns3::StaWifiMac" type. The use of +``NqosWifiMacHelper`` will ensure that the "QosSupported" +``Attribute`` for created MAC objects is set false. The combination +of these two configurations means that the MAC instance next created +will be a non-QoS non-AP station (STA) in an infrastructure BSS (i.e., +a BSS with an AP). Finally, the "ActiveProbing" ``Attribute`` is +set to false. This means that probe requests will not be sent by MACs +created by this helper. + +Once all the station-specific parameters are fully configured, both at the +MAC and PHY layers, we can invoke our now-familiar ``Install`` method to +create the wifi devices of these stations: + +:: + + NetDeviceContainer staDevices; + staDevices = wifi.Install (phy, mac, wifiStaNodes); + +We have configured Wifi for all of our STA nodes, and now we need to +configure the AP (access point) node. We begin this process by changing +the default ``Attributes`` of the ``NqosWifiMacHelper`` to reflect the +requirements of the AP. + +:: + + mac.SetType ("ns3::ApWifiMac", + "Ssid", SsidValue (ssid), + "BeaconGeneration", BooleanValue (true), + "BeaconInterval", TimeValue (Seconds (2.5))); + +In this case, the ``NqosWifiMacHelper`` is going to create MAC +layers of the "ns3::ApWifiMac", the latter specifying that a MAC +instance configured as an AP should be created, with the helper type +implying that the "QosSupported" ``Attribute`` should be set to +false - disabling 802.11e/WMM-style QoS support at created APs. We +set the "BeaconGeneration" ``Attribute`` to true and also set an +interval between beacons of 2.5 seconds. + +The next lines create the single AP which shares the same set of PHY-level +``Attributes`` (and channel) as the stations: + +:: + + NetDeviceContainer apDevices; + apDevices = wifi.Install (phy, mac, wifiApNode); + +Now, we are going to add mobility models. We want the STA nodes to be mobile, +wandering around inside a bounding box, and we want to make the AP node +stationary. We use the ``MobilityHelper`` to make this easy for us. +First, we instantiate a ``MobilityHelper`` object and set some +``Attributes`` controlling the "position allocator" functionality. + +:: + + MobilityHelper mobility; + + mobility.SetPositionAllocator ("ns3::GridPositionAllocator", + "MinX", DoubleValue (0.0), + "MinY", DoubleValue (0.0), + "DeltaX", DoubleValue (5.0), + "DeltaY", DoubleValue (10.0), + "GridWidth", UintegerValue (3), + "LayoutType", StringValue ("RowFirst")); + +This code tells the mobility helper to use a two-dimensional grid to initially +place the STA nodes. Feel free to explore the Doxygen for class +``ns3::GridPositionAllocator`` to see exactly what is being done. + +We have arranged our nodes on an initial grid, but now we need to tell them +how to move. We choose the ``RandomWalk2dMobilityModel`` which has the +nodes move in a random direction at a random speed around inside a bounding +box. + +:: + + mobility.SetMobilityModel ("ns3::RandomWalk2dMobilityModel", + "Bounds", RectangleValue (Rectangle (-50, 50, -50, 50))); + +We now tell the ``MobilityHelper`` to install the mobility models on the +STA nodes. + +:: + + mobility.Install (wifiStaNodes); + +We want the access point to remain in a fixed position during the simulation. +We accomplish this by setting the mobility model for this node to be the +``ns3::ConstantPositionMobilityModel``: + +:: + + mobility.SetMobilityModel ("ns3::ConstantPositionMobilityModel"); + mobility.Install (wifiApNode); + +We now have our nodes, devices and channels created, and mobility models +chosen for the Wifi nodes, but we have no protocol stacks present. Just as +we have done previously many times, we will use the ``InternetStackHelper`` +to install these stacks. + +:: + + InternetStackHelper stack; + stack.Install (csmaNodes); + stack.Install (wifiApNode); + stack.Install (wifiStaNodes); + +Just as in the ``second.cc`` example script, we are going to use the +``Ipv4AddressHelper`` to assign IP addresses to our device interfaces. +First we use the network 10.1.1.0 to create the two addresses needed for our +two point-to-point devices. Then we use network 10.1.2.0 to assign addresses +to the CSMA network and then we assign addresses from network 10.1.3.0 to +both the STA devices and the AP on the wireless network. + +:: + + Ipv4AddressHelper address; + + address.SetBase ("10.1.1.0", "255.255.255.0"); + Ipv4InterfaceContainer p2pInterfaces; + p2pInterfaces = address.Assign (p2pDevices); + + address.SetBase ("10.1.2.0", "255.255.255.0"); + Ipv4InterfaceContainer csmaInterfaces; + csmaInterfaces = address.Assign (csmaDevices); + + address.SetBase ("10.1.3.0", "255.255.255.0"); + address.Assign (staDevices); + address.Assign (apDevices); + +We put the echo server on the "rightmost" node in the illustration at the +start of the file. We have done this before. + +:: + + UdpEchoServerHelper echoServer (9); + + ApplicationContainer serverApps = echoServer.Install (csmaNodes.Get (nCsma)); + serverApps.Start (Seconds (1.0)); + serverApps.Stop (Seconds (10.0)); + +And we put the echo client on the last STA node we created, pointing it to +the server on the CSMA network. We have also seen similar operations before. + +:: + + UdpEchoClientHelper echoClient (csmaInterfaces.GetAddress (nCsma), 9); + echoClient.SetAttribute ("MaxPackets", UintegerValue (1)); + echoClient.SetAttribute ("Interval", TimeValue (Seconds (1.))); + echoClient.SetAttribute ("PacketSize", UintegerValue (1024)); + + ApplicationContainer clientApps = + echoClient.Install (wifiStaNodes.Get (nWifi - 1)); + clientApps.Start (Seconds (2.0)); + clientApps.Stop (Seconds (10.0)); + +Since we have built an internetwork here, we need to enable internetwork routing +just as we did in the ``second.cc`` example script. + +:: + + Ipv4GlobalRoutingHelper::PopulateRoutingTables (); + +One thing that can surprise some users is the fact that the simulation we just +created will never "naturally" stop. This is because we asked the wireless +access point to generate beacons. It will generate beacons forever, and this +will result in simulator events being scheduled into the future indefinitely, +so we must tell the simulator to stop even though it may have beacon generation +events scheduled. The following line of code tells the simulator to stop so that +we don't simulate beacons forever and enter what is essentially an endless +loop. + +:: + + Simulator::Stop (Seconds (10.0)); + +We create just enough tracing to cover all three networks: + +:: + + pointToPoint.EnablePcapAll ("third"); + phy.EnablePcap ("third", apDevices.Get (0)); + csma.EnablePcap ("third", csmaDevices.Get (0), true); + +These three lines of code will start pcap tracing on both of the point-to-point +nodes that serves as our backbone, will start a promiscuous (monitor) mode +trace on the Wifi network, and will start a promiscuous trace on the CSMA +network. This will let us see all of the traffic with a minimum number of +trace files. + +Finally, we actually run the simulation, clean up and then exit the program. + +:: + + Simulator::Run (); + Simulator::Destroy (); + return 0; + } + +In order to run this example, you have to copy the ``third.cc`` example +script into the scratch directory and use Waf to build just as you did with +the ``second.cc`` example. If you are in the top-level directory of the +repository you would type, + +:: + + cp examples/third.cc scratch/mythird.cc + ./waf + ./waf --run scratch/mythird + +Again, since we have set up the UDP echo applications just as we did in the +``second.cc`` script, you will see similar output. + +:: + + Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' + Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' + 'build' finished successfully (0.407s) + Sent 1024 bytes to 10.1.2.4 + Received 1024 bytes from 10.1.3.3 + Received 1024 bytes from 10.1.2.4 + +Recall that the first message, ``Sent 1024 bytes to 10.1.2.4``," is the +UDP echo client sending a packet to the server. In this case, the client +is on the wireless network (10.1.3.0). The second message, +"``Received 1024 bytes from 10.1.3.3``," is from the UDP echo server, +generated when it receives the echo packet. The final message, +"``Received 1024 bytes from 10.1.2.4``," is from the echo client, indicating +that it has received its echo back from the server. + +If you now go and look in the top level directory, you will find four trace +files from this simulation, two from node zero and two from node one: + +:: + + third-0-0.pcap third-0-1.pcap third-1-0.pcap third-1-1.pcap + +The file "third-0-0.pcap" corresponds to the point-to-point device on node +zero -- the left side of the "backbone". The file "third-1-0.pcap" +corresponds to the point-to-point device on node one -- the right side of the +"backbone". The file "third-0-1.pcap" will be the promiscuous (monitor +mode) trace from the Wifi network and the file "third-1-1.pcap" will be the +promiscuous trace from the CSMA network. Can you verify this by inspecting +the code? + +Since the echo client is on the Wifi network, let's start there. Let's take +a look at the promiscuous (monitor mode) trace we captured on that network. + +:: + + tcpdump -nn -tt -r third-0-1.pcap + +You should see some wifi-looking contents you haven't seen here before: + +:: + + reading from file third-0-1.pcap, link-type IEEE802_11 (802.11) + 0.000025 Beacon () [6.0* 9.0 12.0 18.0 24.0 36.0 48.0 54.0 Mbit] IBSS + 0.000263 Assoc Request () [6.0 9.0 12.0 18.0 24.0 36.0 48.0 54.0 Mbit] + 0.000279 Acknowledgment RA:00:00:00:00:00:07 + 0.000357 Assoc Response AID(0) :: Succesful + 0.000501 Acknowledgment RA:00:00:00:00:00:0a + 0.000748 Assoc Request () [6.0 9.0 12.0 18.0 24.0 36.0 48.0 54.0 Mbit] + 0.000764 Acknowledgment RA:00:00:00:00:00:08 + 0.000842 Assoc Response AID(0) :: Succesful + 0.000986 Acknowledgment RA:00:00:00:00:00:0a + 0.001242 Assoc Request () [6.0 9.0 12.0 18.0 24.0 36.0 48.0 54.0 Mbit] + 0.001258 Acknowledgment RA:00:00:00:00:00:09 + 0.001336 Assoc Response AID(0) :: Succesful + 0.001480 Acknowledgment RA:00:00:00:00:00:0a + 2.000112 arp who-has 10.1.3.4 (ff:ff:ff:ff:ff:ff) tell 10.1.3.3 + 2.000128 Acknowledgment RA:00:00:00:00:00:09 + 2.000206 arp who-has 10.1.3.4 (ff:ff:ff:ff:ff:ff) tell 10.1.3.3 + 2.000487 arp reply 10.1.3.4 is-at 00:00:00:00:00:0a + 2.000659 Acknowledgment RA:00:00:00:00:00:0a + 2.002169 IP 10.1.3.3.49153 > 10.1.2.4.9: UDP, length 1024 + 2.002185 Acknowledgment RA:00:00:00:00:00:09 + 2.009771 arp who-has 10.1.3.3 (ff:ff:ff:ff:ff:ff) tell 10.1.3.4 + 2.010029 arp reply 10.1.3.3 is-at 00:00:00:00:00:09 + 2.010045 Acknowledgment RA:00:00:00:00:00:09 + 2.010231 IP 10.1.2.4.9 > 10.1.3.3.49153: UDP, length 1024 + 2.011767 Acknowledgment RA:00:00:00:00:00:0a + 2.500000 Beacon () [6.0* 9.0 12.0 18.0 24.0 36.0 48.0 54.0 Mbit] IBSS + 5.000000 Beacon () [6.0* 9.0 12.0 18.0 24.0 36.0 48.0 54.0 Mbit] IBSS + 7.500000 Beacon () [6.0* 9.0 12.0 18.0 24.0 36.0 48.0 54.0 Mbit] IBSS + +You can see that the link type is now 802.11 as you would expect. You can +probably understand what is going on and find the IP echo request and response +packets in this trace. We leave it as an exercise to completely parse the +trace dump. + +Now, look at the pcap file of the right side of the point-to-point link, + +:: + + tcpdump -nn -tt -r third-0-0.pcap + +Again, you should see some familiar looking contents: + +:: + + reading from file third-0-0.pcap, link-type PPP (PPP) + 2.002169 IP 10.1.3.3.49153 > 10.1.2.4.9: UDP, length 1024 + 2.009771 IP 10.1.2.4.9 > 10.1.3.3.49153: UDP, length 1024 + +This is the echo packet going from left to right (from Wifi to CSMA) and back +again across the point-to-point link. + +Now, look at the pcap file of the right side of the point-to-point link, + +:: + + tcpdump -nn -tt -r third-1-0.pcap + +Again, you should see some familiar looking contents: + +:: + + reading from file third-1-0.pcap, link-type PPP (PPP) + 2.005855 IP 10.1.3.3.49153 > 10.1.2.4.9: UDP, length 1024 + 2.006084 IP 10.1.2.4.9 > 10.1.3.3.49153: UDP, length 1024 + +This is also the echo packet going from left to right (from Wifi to CSMA) and +back again across the point-to-point link with slightly different timings +as you might expect. + +The echo server is on the CSMA network, let's look at the promiscuous trace +there: + +:: + + tcpdump -nn -tt -r third-1-1.pcap + +You should see some familiar looking contents: + +:: + + reading from file third-1-1.pcap, link-type EN10MB (Ethernet) + 2.005855 arp who-has 10.1.2.4 (ff:ff:ff:ff:ff:ff) tell 10.1.2.1 + 2.005877 arp reply 10.1.2.4 is-at 00:00:00:00:00:06 + 2.005877 IP 10.1.3.3.49153 > 10.1.2.4.9: UDP, length 1024 + 2.005980 arp who-has 10.1.2.1 (ff:ff:ff:ff:ff:ff) tell 10.1.2.4 + 2.005980 arp reply 10.1.2.1 is-at 00:00:00:00:00:03 + 2.006084 IP 10.1.2.4.9 > 10.1.3.3.49153: UDP, length 1024 + +This should be easily understood. If you've forgotten, go back and look at +the discussion in ``second.cc``. This is the same sequence. + +Now, we spent a lot of time setting up mobility models for the wireless network +and so it would be a shame to finish up without even showing that the STA +nodes are actually moving around during the simulation. Let's do this by hooking +into the ``MobilityModel`` course change trace source. This is just a sneak +peek into the detailed tracing section which is coming up, but this seems a very +nice place to get an example in. + +As mentioned in the "Tweaking ns-3" section, the |ns3| tracing system +is divided into trace sources and trace sinks, and we provide functions to +connect the two. We will use the mobility model predefined course change +trace source to originate the trace events. We will need to write a trace +sink to connect to that source that will display some pretty information for +us. Despite its reputation as being difficult, it's really quite simple. +Just before the main program of the ``scratch/mythird.cc`` script, add the +following function: + +:: + + void + CourseChange (std::string context, Ptr model) + { + Vector position = model->GetPosition (); + NS_LOG_UNCOND (context << + " x = " << position.x << ", y = " << position.y); + } + +This code just pulls the position information from the mobility model and +unconditionally logs the x and y position of the node. We are +going to arrange for this function to be called every time the wireless +node with the echo client changes its position. We do this using the +``Config::Connect`` function. Add the following lines of code to the +script just before the ``Simulator::Run`` call. + +:: + + std::ostringstream oss; + oss << + "/NodeList/" << wifiStaNodes.Get (nWifi - 1)->GetId () << + "/$ns3::MobilityModel/CourseChange"; + + Config::Connect (oss.str (), MakeCallback (&CourseChange)); + +What we do here is to create a string containing the tracing namespace path +of the event to which we want to connect. First, we have to figure out which +node it is we want using the ``GetId`` method as described earlier. In the +case of the default number of CSMA and wireless nodes, this turns out to be +node seven and the tracing namespace path to the mobility model would look +like, + +:: + + /NodeList/7/$ns3::MobilityModel/CourseChange + +Based on the discussion in the tracing section, you may infer that this trace +path references the seventh node in the global NodeList. It specifies +what is called an aggregated object of type ``ns3::MobilityModel``. The +dollar sign prefix implies that the MobilityModel is aggregated to node seven. +The last component of the path means that we are hooking into the +"CourseChange" event of that model. + +We make a connection between the trace source in node seven with our trace +sink by calling ``Config::Connect`` and passing this namespace path. Once +this is done, every course change event on node seven will be hooked into our +trace sink, which will in turn print out the new position. + +If you now run the simulation, you will see the course changes displayed as +they happen. + +:: + + Build finished successfully (00:00:01) + /NodeList/7/$ns3::MobilityModel/CourseChange x = 10, y = 0 + /NodeList/7/$ns3::MobilityModel/CourseChange x = 9.41539, y = -0.811313 + /NodeList/7/$ns3::MobilityModel/CourseChange x = 8.46199, y = -1.11303 + /NodeList/7/$ns3::MobilityModel/CourseChange x = 7.52738, y = -1.46869 + /NodeList/7/$ns3::MobilityModel/CourseChange x = 6.67099, y = -1.98503 + /NodeList/7/$ns3::MobilityModel/CourseChange x = 5.6835, y = -2.14268 + /NodeList/7/$ns3::MobilityModel/CourseChange x = 4.70932, y = -1.91689 + Sent 1024 bytes to 10.1.2.4 + Received 1024 bytes from 10.1.3.3 + Received 1024 bytes from 10.1.2.4 + /NodeList/7/$ns3::MobilityModel/CourseChange x = 5.53175, y = -2.48576 + /NodeList/7/$ns3::MobilityModel/CourseChange x = 4.58021, y = -2.17821 + /NodeList/7/$ns3::MobilityModel/CourseChange x = 4.18915, y = -1.25785 + /NodeList/7/$ns3::MobilityModel/CourseChange x = 4.7572, y = -0.434856 + /NodeList/7/$ns3::MobilityModel/CourseChange x = 4.62404, y = 0.556238 + /NodeList/7/$ns3::MobilityModel/CourseChange x = 4.74127, y = 1.54934 + /NodeList/7/$ns3::MobilityModel/CourseChange x = 5.73934, y = 1.48729 + /NodeList/7/$ns3::MobilityModel/CourseChange x = 6.18521, y = 0.59219 + /NodeList/7/$ns3::MobilityModel/CourseChange x = 6.58121, y = 1.51044 + /NodeList/7/$ns3::MobilityModel/CourseChange x = 7.27897, y = 2.22677 + /NodeList/7/$ns3::MobilityModel/CourseChange x = 6.42888, y = 1.70014 + /NodeList/7/$ns3::MobilityModel/CourseChange x = 7.40519, y = 1.91654 + /NodeList/7/$ns3::MobilityModel/CourseChange x = 6.51981, y = 1.45166 + /NodeList/7/$ns3::MobilityModel/CourseChange x = 7.34588, y = 2.01523 + /NodeList/7/$ns3::MobilityModel/CourseChange x = 7.81046, y = 2.90077 + /NodeList/7/$ns3::MobilityModel/CourseChange x = 6.89186, y = 3.29596 + /NodeList/7/$ns3::MobilityModel/CourseChange x = 7.46617, y = 2.47732 + /NodeList/7/$ns3::MobilityModel/CourseChange x = 7.05492, y = 1.56579 + /NodeList/7/$ns3::MobilityModel/CourseChange x = 8.00393, y = 1.25054 + /NodeList/7/$ns3::MobilityModel/CourseChange x = 7.00968, y = 1.35768 + /NodeList/7/$ns3::MobilityModel/CourseChange x = 7.33503, y = 2.30328 + /NodeList/7/$ns3::MobilityModel/CourseChange x = 7.18682, y = 3.29223 + /NodeList/7/$ns3::MobilityModel/CourseChange x = 7.96865, y = 2.66873 diff -r c9133c87760d -r 7ff69b244b5b doc/tutorial/source/conceptual-overview.rst --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/tutorial/source/conceptual-overview.rst Sun Jan 02 22:57:32 2011 -0800 @@ -0,0 +1,840 @@ +.. include:: replace.txt + + +Conceptual Overview +------------------- + +The first thing we need to do before actually starting to look at or write +|ns3| code is to explain a few core concepts and abstractions in the +system. Much of this may appear transparently obvious to some, but we +recommend taking the time to read through this section just to ensure you +are starting on a firm foundation. + +Key Abstractions +**************** + +In this section, we'll review some terms that are commonly used in +networking, but have a specific meaning in |ns3|. + +Node +++++ +In Internet jargon, a computing device that connects to a network is called +a *host* or sometimes an *end system*. Because |ns3| is a +*network* simulator, not specifically an *Internet* simulator, we +intentionally do not use the term host since it is closely associated with +the Internet and its protocols. Instead, we use a more generic term also +used by other simulators that originates in Graph Theory --- the *node*. + +In |ns3| the basic computing device abstraction is called the +node. This abstraction is represented in C++ by the class ``Node``. The +``Node`` class provides methods for managing the representations of +computing devices in simulations. + +You should think of a ``Node`` as a computer to which you will add +functionality. One adds things like applications, protocol stacks and +peripheral cards with their associated drivers to enable the computer to do +useful work. We use the same basic model in |ns3|. + +Application ++++++++++++ +Typically, computer software is divided into two broad classes. *System +Software* organizes various computer resources such as memory, processor +cycles, disk, network, etc., according to some computing model. System +software usually does not use those resources to complete tasks that directly +benefit a user. A user would typically run an *application* that acquires +and uses the resources controlled by the system software to accomplish some +goal. + +Often, the line of separation between system and application software is made +at the privilege level change that happens in operating system traps. +In |ns3| there is no real concept of operating system and especially +no concept of privilege levels or system calls. We do, however, have the +idea of an application. Just as software applications run on computers to +perform tasks in the "real world," |ns3| applications run on +|ns3| ``Nodes`` to drive simulations in the simulated world. + +In |ns3| the basic abstraction for a user program that generates some +activity to be simulated is the application. This abstraction is represented +in C++ by the class ``Application``. The ``Application`` class provides +methods for managing the representations of our version of user-level +applications in simulations. Developers are expected to specialize the +``Application`` class in the object-oriented programming sense to create new +applications. In this tutorial, we will use specializations of class +``Application`` called ``UdpEchoClientApplication`` and +``UdpEchoServerApplication``. As you might expect, these applications +compose a client/server application set used to generate and echo simulated +network packets + +Channel ++++++++ + +In the real world, one can connect a computer to a network. Often the media +over which data flows in these networks are called *channels*. When +you connect your Ethernet cable to the plug in the wall, you are connecting +your computer to an Ethernet communication channel. In the simulated world +of |ns3|, one connects a ``Node`` to an object representing a +communication channel. Here the basic communication subnetwork abstraction +is called the channel and is represented in C++ by the class ``Channel``. + +The ``Channel`` class provides methods for managing communication +subnetwork objects and connecting nodes to them. ``Channels`` may also be +specialized by developers in the object oriented programming sense. A +``Channel`` specialization may model something as simple as a wire. The +specialized ``Channel`` can also model things as complicated as a large +Ethernet switch, or three-dimensional space full of obstructions in the case +of wireless networks. + +We will use specialized versions of the ``Channel`` called +``CsmaChannel``, ``PointToPointChannel`` and ``WifiChannel`` in this +tutorial. The ``CsmaChannel``, for example, models a version of a +communication subnetwork that implements a *carrier sense multiple +access* communication medium. This gives us Ethernet-like functionality. + +Net Device +++++++++++ +It used to be the case that if you wanted to connect a computers to a network, +you had to buy a specific kind of network cable and a hardware device called +(in PC terminology) a *peripheral card* that needed to be installed in +your computer. If the peripheral card implemented some networking function, +they were called Network Interface Cards, or *NICs*. Today most +computers come with the network interface hardware built in and users don't +see these building blocks. + +A NIC will not work without a software driver to control the hardware. In +Unix (or Linux), a piece of peripheral hardware is classified as a +*device*. Devices are controlled using *device drivers*, and network +devices (NICs) are controlled using *network device drivers* +collectively known as *net devices*. In Unix and Linux you refer +to these net devices by names such as *eth0*. + +In |ns3| the *net device* abstraction covers both the software +driver and the simulated hardware. A net device is "installed" in a +``Node`` in order to enable the ``Node`` to communicate with other +``Nodes`` in the simulation via ``Channels``. Just as in a real +computer, a ``Node`` may be connected to more than one ``Channel`` via +multiple ``NetDevices``. + +The net device abstraction is represented in C++ by the class ``NetDevice``. +The ``NetDevice`` class provides methods for managing connections to +``Node`` and ``Channel`` objects; and may be specialized by developers +in the object-oriented programming sense. We will use the several specialized +versions of the ``NetDevice`` called ``CsmaNetDevice``, +``PointToPointNetDevice``, and ``WifiNetDevice`` in this tutorial. +Just as an Ethernet NIC is designed to work with an Ethernet network, the +``CsmaNetDevice`` is designed to work with a ``CsmaChannel``; the +``PointToPointNetDevice`` is designed to work with a +``PointToPointChannel`` and a ``WifiNetNevice`` is designed to work with +a ``WifiChannel``. + +Topology Helpers +++++++++++++++++ +In a real network, you will find host computers with added (or built-in) +NICs. In |ns3| we would say that you will find ``Nodes`` with +attached ``NetDevices``. In a large simulated network you will need to +arrange many connections between ``Nodes``, ``NetDevices`` and +``Channels``. + +Since connecting ``NetDevices`` to ``Nodes``, ``NetDevices`` +to ``Channels``, assigning IP addresses, etc., are such common tasks +in |ns3|, we provide what we call *topology helpers* to make +this as easy as possible. For example, it may take many distinct +|ns3| core operations to create a NetDevice, add a MAC address, +install that net device on a ``Node``, configure the node's protocol stack, +and then connect the ``NetDevice`` to a ``Channel``. Even more +operations would be required to connect multiple devices onto multipoint +channels and then to connect individual networks together into internetworks. +We provide topology helper objects that combine those many distinct operations +into an easy to use model for your convenience. + +A First ns-3 Script +******************* +If you downloaded the system as was suggested above, you will have a release +of |ns3| in a directory called ``repos`` under your home +directory. Change into that release directory, and you should find a +directory structure something like the following: + +:: + + AUTHORS doc/ README src/ waf.bat* + bindings/ examples/ RELEASE_NOTES utils/ wscript + build/ LICENSE samples/ VERSION wutils.py + CHANGES.html ns3/ scratch/ waf* wutils.pyc + +Change into the ``examples/tutorial`` directory. You should see a file named +``first.cc`` located there. This is a script that will create a simple +point-to-point link between two nodes and echo a single packet between the +nodes. Let's take a look at that script line by line, so go ahead and open +``first.cc`` in your favorite editor. + +Boilerplate ++++++++++++ +The first line in the file is an emacs mode line. This tells emacs about the +formatting conventions (coding style) we use in our source code. + +:: + + /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ + +This is always a somewhat controversial subject, so we might as well get it +out of the way immediately. The |ns3| project, like most large +projects, has adopted a coding style to which all contributed code must +adhere. If you want to contribute your code to the project, you will +eventually have to conform to the |ns3| coding standard as described +in the file ``doc/codingstd.txt`` or shown on the project web page +`here +`_. + +We recommend that you, well, just get used to the look and feel of |ns3| +code and adopt this standard whenever you are working with our code. All of +the development team and contributors have done so with various amounts of +grumbling. The emacs mode line above makes it easier to get the formatting +correct if you use the emacs editor. + +The |ns3| simulator is licensed using the GNU General Public +License. You will see the appropriate GNU legalese at the head of every file +in the |ns3| distribution. Often you will see a copyright notice for +one of the institutions involved in the |ns3| project above the GPL +text and an author listed below. + +:: + + /* + * 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 + */ + +Module Includes ++++++++++++++++ +The code proper starts with a number of include statements. + +:: + + #include "ns3/core-module.h" + #include "ns3/simulator-module.h" + #include "ns3/node-module.h" + #include "ns3/helper-module.h" + +To help our high-level script users deal with the large number of include +files present in the system, we group includes according to relatively large +modules. We provide a single include file that will recursively load all of +the include files used in each module. Rather than having to look up exactly +what header you need, and possibly have to get a number of dependencies right, +we give you the ability to load a group of files at a large granularity. This +is not the most efficient approach but it certainly makes writing scripts much +easier. + +Each of the |ns3| include files is placed in a directory called +``ns3`` (under the build directory) during the build process to help avoid +include file name collisions. The ``ns3/core-module.h`` file corresponds +to the ns-3 module you will find in the directory ``src/core`` in your +downloaded release distribution. If you list this directory you will find a +large number of header files. When you do a build, Waf will place public +header files in an ``ns3`` directory under the appropriate +``build/debug`` or ``build/optimized`` directory depending on your +configuration. Waf will also automatically generate a module include file to +load all of the public header files. + +Since you are, of course, following this tutorial religiously, you will +already have done a + +:: + + ./waf -d debug configure + +in order to configure the project to perform debug builds. You will also have +done a + +:: + + ./waf + +to build the project. So now if you look in the directory +``../../build/debug/ns3`` you will find the four module include files shown +above. You can take a look at the contents of these files and find that they +do include all of the public include files in their respective modules. + +Ns3 Namespace ++++++++++++++ +The next line in the ``first.cc`` script is a namespace declaration. + +:: + + using namespace ns3; + +The |ns3| project is implemented in a C++ namespace called +``ns3``. This groups all |ns3|-related declarations in a scope +outside the global namespace, which we hope will help with integration with +other code. The C++ ``using`` statement introduces the |ns3| +namespace into the current (global) declarative region. This is a fancy way +of saying that after this declaration, you will not have to type ``ns3::`` +scope resolution operator before all of the |ns3| code in order to use +it. If you are unfamiliar with namespaces, please consult almost any C++ +tutorial and compare the ``ns3`` namespace and usage here with instances of +the ``std`` namespace and the ``using namespace std;`` statements you +will often find in discussions of ``cout`` and streams. + +Logging ++++++++ +The next line of the script is the following, + +:: + + NS_LOG_COMPONENT_DEFINE ("FirstScriptExample"); + +We will use this statement as a convenient place to talk about our Doxygen +documentation system. If you look at the project web site, +`ns-3 project +`_, you will find a link to "Doxygen +(ns-3-dev)" in the navigation bar. If you select this link, you will be +taken to our documentation page for the current development release. There +is also a link to "Doxygen (stable)" that will take you to the documentation +for the latest stable release of |ns3|. + +Along the left side, you will find a graphical representation of the structure +of the documentation. A good place to start is the ``NS-3 Modules`` +"book" in the |ns3| navigation tree. If you expand ``Modules`` +you will see a list of |ns3| module documentation. The concept of +module here ties directly into the module include files discussed above. It +turns out that the |ns3| logging subsystem is part of the ``core`` +module, so go ahead and expand that documentation node. Now, expand the +``Debugging`` book and then select the ``Logging`` page. + +You should now be looking at the Doxygen documentation for the Logging module. +In the list of ``#define``s at the top of the page you will see the entry +for ``NS_LOG_COMPONENT_DEFINE``. Before jumping in, it would probably be +good to look for the "Detailed Description" of the logging module to get a +feel for the overall operation. You can either scroll down or select the +"More..." link under the collaboration diagram to do this. + +Once you have a general idea of what is going on, go ahead and take a look at +the specific ``NS_LOG_COMPONENT_DEFINE`` documentation. I won't duplicate +the documentation here, but to summarize, this line declares a logging +component called ``FirstScriptExample`` that allows you to enable and +disable console message logging by reference to the name. + +Main Function ++++++++++++++ +The next lines of the script you will find are, + +:: + + int + main (int argc, char *argv[]) + { + +This is just the declaration of the main function of your program (script). +Just as in any C++ program, you need to define a main function that will be +the first function run. There is nothing at all special here. Your +|ns3| script is just a C++ program. + +The next two lines of the script are used to enable two logging components that +are built into the Echo Client and Echo Server applications: + +:: + + LogComponentEnable("UdpEchoClientApplication", LOG_LEVEL_INFO); + LogComponentEnable("UdpEchoServerApplication", LOG_LEVEL_INFO); + +If you have read over the Logging component documentation you will have seen +that there are a number of levels of logging verbosity/detail that you can +enable on each component. These two lines of code enable debug logging at the +INFO level for echo clients and servers. This will result in the application +printing out messages as packets are sent and received during the simulation. + +Now we will get directly to the business of creating a topology and running +a simulation. We use the topology helper objects to make this job as +easy as possible. + +Topology Helpers +++++++++++++++++ +NodeContainer +~~~~~~~~~~~~~ +The next two lines of code in our script will actually create the +|ns3| ``Node`` objects that will represent the computers in the +simulation. + +:: + + NodeContainer nodes; + nodes.Create (2); + +Let's find the documentation for the ``NodeContainer`` class before we +continue. Another way to get into the documentation for a given class is via +the ``Classes`` tab in the Doxygen pages. If you still have the Doxygen +handy, just scroll up to the top of the page and select the ``Classes`` +tab. You should see a new set of tabs appear, one of which is +``Class List``. Under that tab you will see a list of all of the +|ns3| classes. Scroll down, looking for ``ns3::NodeContainer``. +When you find the class, go ahead and select it to go to the documentation for +the class. + +You may recall that one of our key abstractions is the ``Node``. This +represents a computer to which we are going to add things like protocol stacks, +applications and peripheral cards. The ``NodeContainer`` topology helper +provides a convenient way to create, manage and access any ``Node`` objects +that we create in order to run a simulation. The first line above just +declares a NodeContainer which we call ``nodes``. The second line calls the +``Create`` method on the ``nodes`` object and asks the container to +create two nodes. As described in the Doxygen, the container calls down into +the |ns3| system proper to create two ``Node`` objects and stores +pointers to those objects internally. + +The nodes as they stand in the script do nothing. The next step in +constructing a topology is to connect our nodes together into a network. +The simplest form of network we support is a single point-to-point link +between two nodes. We'll construct one of those links here. + +PointToPointHelper +~~~~~~~~~~~~~~~~~~ +We are constructing a point to point link, and, in a pattern which will become +quite familiar to you, we use a topology helper object to do the low-level +work required to put the link together. Recall that two of our key +abstractions are the ``NetDevice`` and the ``Channel``. In the real +world, these terms correspond roughly to peripheral cards and network cables. +Typically these two things are intimately tied together and one cannot expect +to interchange, for example, Ethernet devices and wireless channels. Our +Topology Helpers follow this intimate coupling and therefore you will use a +single ``PointToPointHelper`` to configure and connect |ns3| +``PointToPointNetDevice`` and ``PointToPointChannel`` objects in this +script. + +The next three lines in the script are, + +:: + + PointToPointHelper pointToPoint; + pointToPoint.SetDeviceAttribute ("DataRate", StringValue ("5Mbps")); + pointToPoint.SetChannelAttribute ("Delay", StringValue ("2ms")); + +The first line, + +:: + + PointToPointHelper pointToPoint; + +instantiates a ``PointToPointHelper`` object on the stack. From a +high-level perspective the next line, + +:: + + pointToPoint.SetDeviceAttribute ("DataRate", StringValue ("5Mbps")); + +tells the ``PointToPointHelper`` object to use the value "5Mbps" +(five megabits per second) as the "DataRate" when it creates a +``PointToPointNetDevice`` object. + +From a more detailed perspective, the string "DataRate" corresponds +to what we call an ``Attribute`` of the ``PointToPointNetDevice``. +If you look at the Doxygen for class ``ns3::PointToPointNetDevice`` and +find the documentation for the ``GetTypeId`` method, you will find a list +of ``Attributes`` defined for the device. Among these is the "DataRate" +``Attribute``. Most user-visible |ns3| objects have similar lists of +``Attributes``. We use this mechanism to easily configure simulations without +recompiling as you will see in a following section. + +Similar to the "DataRate" on the ``PointToPointNetDevice`` you will find a +"Delay" ``Attribute`` associated with the ``PointToPointChannel``. The +final line, + +:: + + pointToPoint.SetChannelAttribute ("Delay", StringValue ("2ms")); + +tells the ``PointToPointHelper`` to use the value "2ms" (two milliseconds) +as the value of the transmission delay of every point to point channel it +subsequently creates. + +NetDeviceContainer +~~~~~~~~~~~~~~~~~~ +At this point in the script, we have a ``NodeContainer`` that contains +two nodes. We have a ``PointToPointHelper`` that is primed and ready to +make ``PointToPointNetDevices`` and wire ``PointToPointChannel`` objects +between them. Just as we used the ``NodeContainer`` topology helper object +to create the ``Nodes`` for our simulation, we will ask the +``PointToPointHelper`` to do the work involved in creating, configuring and +installing our devices for us. We will need to have a list of all of the +NetDevice objects that are created, so we use a NetDeviceContainer to hold +them just as we used a NodeContainer to hold the nodes we created. The +following two lines of code, + +:: + + NetDeviceContainer devices; + devices = pointToPoint.Install (nodes); + +will finish configuring the devices and channel. The first line declares the +device container mentioned above and the second does the heavy lifting. The +``Install`` method of the ``PointToPointHelper`` takes a +``NodeContainer`` as a parameter. Internally, a ``NetDeviceContainer`` +is created. For each node in the ``NodeContainer`` (there must be exactly +two for a point-to-point link) a ``PointToPointNetDevice`` is created and +saved in the device container. A ``PointToPointChannel`` is created and +the two ``PointToPointNetDevices`` are attached. When objects are created +by the ``PointToPointHelper``, the ``Attributes`` previously set in the +helper are used to initialize the corresponding ``Attributes`` in the +created objects. + +After executing the ``pointToPoint.Install (nodes)`` call we will have +two nodes, each with an installed point-to-point net device and a single +point-to-point channel between them. Both devices will be configured to +transmit data at five megabits per second over the channel which has a two +millisecond transmission delay. + +InternetStackHelper +~~~~~~~~~~~~~~~~~~~ +We now have nodes and devices configured, but we don't have any protocol stacks +installed on our nodes. The next two lines of code will take care of that. + +:: + + InternetStackHelper stack; + stack.Install (nodes); + +The ``InternetStackHelper`` is a topology helper that is to internet stacks +what the ``PointToPointHelper`` is to point-to-point net devices. The +``Install`` method takes a ``NodeContainer`` as a parameter. When it is +executed, it will install an Internet Stack (TCP, UDP, IP, etc.) on each of +the nodes in the node container. + +Ipv4AddressHelper +~~~~~~~~~~~~~~~~~ +Next we need to associate the devices on our nodes with IP addresses. We +provide a topology helper to manage the allocation of IP addresses. The only +user-visible API is to set the base IP address and network mask to use when +performing the actual address allocation (which is done at a lower level +inside the helper). + +The next two lines of code in our example script, ``first.cc``, + +:: + + Ipv4AddressHelper address; + address.SetBase ("10.1.1.0", "255.255.255.0"); + +declare an address helper object and tell it that it should begin allocating IP +addresses from the network 10.1.1.0 using the mask 255.255.255.0 to define +the allocatable bits. By default the addresses allocated will start at one +and increase monotonically, so the first address allocated from this base will +be 10.1.1.1, followed by 10.1.1.2, etc. The low level |ns3| system +actually remembers all of the IP addresses allocated and will generate a +fatal error if you accidentally cause the same address to be generated twice +(which is a very hard to debug error, by the way). + +The next line of code, + +:: + + Ipv4InterfaceContainer interfaces = address.Assign (devices); + +performs the actual address assignment. In |ns3| we make the +association between an IP address and a device using an ``Ipv4Interface`` +object. Just as we sometimes need a list of net devices created by a helper +for future reference we sometimes need a list of ``Ipv4Interface`` objects. +The ``Ipv4InterfaceContainer`` provides this functionality. + +Now we have a point-to-point network built, with stacks installed and IP +addresses assigned. What we need at this point are applications to generate +traffic. + +Applications +++++++++++++ +Another one of the core abstractions of the ns-3 system is the +``Application``. In this script we use two specializations of the core +|ns3| class ``Application`` called ``UdpEchoServerApplication`` +and ``UdpEchoClientApplication``. Just as we have in our previous +explanations, we use helper objects to help configure and manage the +underlying objects. Here, we use ``UdpEchoServerHelper`` and +``UdpEchoClientHelper`` objects to make our lives easier. + +UdpEchoServerHelper +~~~~~~~~~~~~~~~~~~~ +The following lines of code in our example script, ``first.cc``, are used +to set up a UDP echo server application on one of the nodes we have previously +created. + +:: + + UdpEchoServerHelper echoServer (9); + + ApplicationContainer serverApps = echoServer.Install (nodes.Get (1)); + serverApps.Start (Seconds (1.0)); + serverApps.Stop (Seconds (10.0)); + +The first line of code in the above snippet declares the +``UdpEchoServerHelper``. As usual, this isn't the application itself, it +is an object used to help us create the actual applications. One of our +conventions is to place *required* ``Attributes`` in the helper constructor. +In this case, the helper can't do anything useful unless it is provided with +a port number that the client also knows about. Rather than just picking one +and hoping it all works out, we require the port number as a parameter to the +constructor. The constructor, in turn, simply does a ``SetAttribute`` +with the passed value. If you want, you can set the "Port" ``Attribute`` +to another value later using ``SetAttribute``. + +Similar to many other helper objects, the ``UdpEchoServerHelper`` object +has an ``Install`` method. It is the execution of this method that actually +causes the underlying echo server application to be instantiated and attached +to a node. Interestingly, the ``Install`` method takes a +``NodeContainter`` as a parameter just as the other ``Install`` methods +we have seen. This is actually what is passed to the method even though it +doesn't look so in this case. There is a C++ *implicit conversion* at +work here that takes the result of ``nodes.Get (1)`` (which returns a smart +pointer to a node object --- ``Ptr``) and uses that in a constructor +for an unnamed ``NodeContainer`` that is then passed to ``Install``. +If you are ever at a loss to find a particular method signature in C++ code +that compiles and runs just fine, look for these kinds of implicit conversions. + +We now see that ``echoServer.Install`` is going to install a +``UdpEchoServerApplication`` on the node found at index number one of the +``NodeContainer`` we used to manage our nodes. ``Install`` will return +a container that holds pointers to all of the applications (one in this case +since we passed a ``NodeContainer`` containing one node) created by the +helper. + +Applications require a time to "start" generating traffic and may take an +optional time to "stop". We provide both. These times are set using the +``ApplicationContainer`` methods ``Start`` and ``Stop``. These +methods take ``Time`` parameters. In this case, we use an *explicit* +C++ conversion sequence to take the C++ double 1.0 and convert it to an +|ns3| ``Time`` object using a ``Seconds`` cast. Be aware that +the conversion rules may be controlled by the model author, and C++ has its +own rules, so you can't always just assume that parameters will be happily +converted for you. The two lines, + +:: + + serverApps.Start (Seconds (1.0)); + serverApps.Stop (Seconds (10.0)); + +will cause the echo server application to ``Start`` (enable itself) at one +second into the simulation and to ``Stop`` (disable itself) at ten seconds +into the simulation. By virtue of the fact that we have declared a simulation +event (the application stop event) to be executed at ten seconds, the simulation +will last *at least* ten seconds. + +UdpEchoClientHelper +~~~~~~~~~~~~~~~~~~~ + +The echo client application is set up in a method substantially similar to +that for the server. There is an underlying ``UdpEchoClientApplication`` +that is managed by an ``UdpEchoClientHelper``. + +:: + + UdpEchoClientHelper echoClient (interfaces.GetAddress (1), 9); + echoClient.SetAttribute ("MaxPackets", UintegerValue (1)); + echoClient.SetAttribute ("Interval", TimeValue (Seconds (1.))); + echoClient.SetAttribute ("PacketSize", UintegerValue (1024)); + + ApplicationContainer clientApps = echoClient.Install (nodes.Get (0)); + clientApps.Start (Seconds (2.0)); + clientApps.Stop (Seconds (10.0)); + +For the echo client, however, we need to set five different ``Attributes``. +The first two ``Attributes`` are set during construction of the +``UdpEchoClientHelper``. We pass parameters that are used (internally to +the helper) to set the "RemoteAddress" and "RemotePort" ``Attributes`` +in accordance with our convention to make required ``Attributes`` parameters +in the helper constructors. + +Recall that we used an ``Ipv4InterfaceContainer`` to keep track of the IP +addresses we assigned to our devices. The zeroth interface in the +``interfaces`` container is going to correspond to the IP address of the +zeroth node in the ``nodes`` container. The first interface in the +``interfaces`` container corresponds to the IP address of the first node +in the ``nodes`` container. So, in the first line of code (from above), we +are creating the helper and telling it so set the remote address of the client +to be the IP address assigned to the node on which the server resides. We +also tell it to arrange to send packets to port nine. + +The "MaxPackets" ``Attribute`` tells the client the maximum number of +packets we allow it to send during the simulation. The "Interval" +``Attribute`` tells the client how long to wait between packets, and the +"PacketSize" ``Attribute`` tells the client how large its packet payloads +should be. With this particular combination of ``Attributes``, we are +telling the client to send one 1024-byte packet. + +Just as in the case of the echo server, we tell the echo client to ``Start`` +and ``Stop``, but here we start the client one second after the server is +enabled (at two seconds into the simulation). + +Simulator ++++++++++ +What we need to do at this point is to actually run the simulation. This is +done using the global function ``Simulator::Run``. + +:: + + Simulator::Run (); + +When we previously called the methods, + +:: + + serverApps.Start (Seconds (1.0)); + serverApps.Stop (Seconds (10.0)); + ... + clientApps.Start (Seconds (2.0)); + clientApps.Stop (Seconds (10.0)); + +we actually scheduled events in the simulator at 1.0 seconds, 2.0 seconds and +two events at 10.0 seconds. When ``Simulator::Run`` is called, the system +will begin looking through the list of scheduled events and executing them. +First it will run the event at 1.0 seconds, which will enable the echo server +application (this event may, in turn, schedule many other events). Then it +will run the event scheduled for t=2.0 seconds which will start the echo client +application. Again, this event may schedule many more events. The start event +implementation in the echo client application will begin the data transfer phase +of the simulation by sending a packet to the server. + +The act of sending the packet to the server will trigger a chain of events +that will be automatically scheduled behind the scenes and which will perform +the mechanics of the packet echo according to the various timing parameters +that we have set in the script. + +Eventually, since we only send one packet (recall the ``MaxPackets`` +``Attribute`` was set to one), the chain of events triggered by +that single client echo request will taper off and the simulation will go +idle. Once this happens, the remaining events will be the ``Stop`` events +for the server and the client. When these events are executed, there are +no further events to process and ``Simulator::Run`` returns. The simulation +is then complete. + +All that remains is to clean up. This is done by calling the global function +``Simulator::Destroy``. As the helper functions (or low level +|ns3| code) executed, they arranged it so that hooks were inserted in +the simulator to destroy all of the objects that were created. You did not +have to keep track of any of these objects yourself --- all you had to do +was to call ``Simulator::Destroy`` and exit. The |ns3| system +took care of the hard part for you. The remaining lines of our first +|ns3| script, ``first.cc``, do just that: + +:: + + Simulator::Destroy (); + return 0; + } + +Building Your Script +++++++++++++++++++++ +We have made it trivial to build your simple scripts. All you have to do is +to drop your script into the scratch directory and it will automatically be +built if you run Waf. Let's try it. Copy ``examples/tutorial/first.cc`` into +the ``scratch`` directory after changing back into the top level directory. + +:: + + cd .. + cp examples/tutorial/first.cc scratch/myfirst.cc + +Now build your first example script using waf: + +:: + + ./waf + +You should see messages reporting that your ``myfirst`` example was built +successfully. + +:: + + Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' + [614/708] cxx: scratch/myfirst.cc -> build/debug/scratch/myfirst_3.o + [706/708] cxx_link: build/debug/scratch/myfirst_3.o -> build/debug/scratch/myfirst + Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' + 'build' finished successfully (2.357s) + +You can now run the example (note that if you build your program in the scratch +directory you must run it out of the scratch directory): + +:: + + ./waf --run scratch/myfirst + +You should see some output: + +:: + + Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' + Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' + 'build' finished successfully (0.418s) + Sent 1024 bytes to 10.1.1.2 + Received 1024 bytes from 10.1.1.1 + Received 1024 bytes from 10.1.1.2 + +Here you see that the build system checks to make sure that the file has been +build and then runs it. You see the logging component on the echo client +indicate that it has sent one 1024 byte packet to the Echo Server on +10.1.1.2. You also see the logging component on the echo server say that +it has received the 1024 bytes from 10.1.1.1. The echo server silently +echoes the packet and you see the echo client log that it has received its +packet back from the server. + +Ns-3 Source Code +**************** + +Now that you have used some of the |ns3| helpers you may want to +have a look at some of the source code that implements that functionality. +The most recent code can be browsed on our web server at the following link: +http://code.nsnam.org/ns-3-dev. There, you will see the Mercurial +summary page for our |ns3| development tree. + +At the top of the page, you will see a number of links, + +:: + + summary | shortlog | changelog | graph | tags | files + +Go ahead and select the ``files`` link. This is what the top-level of +most of our *repositories* will look: + +:: + + drwxr-xr-x [up] + drwxr-xr-x bindings python files + drwxr-xr-x doc files + drwxr-xr-x examples files + drwxr-xr-x ns3 files + drwxr-xr-x samples files + drwxr-xr-x scratch files + drwxr-xr-x src files + drwxr-xr-x utils files + -rw-r--r-- 2009-07-01 12:47 +0200 560 .hgignore file | revisions | annotate + -rw-r--r-- 2009-07-01 12:47 +0200 1886 .hgtags file | revisions | annotate + -rw-r--r-- 2009-07-01 12:47 +0200 1276 AUTHORS file | revisions | annotate + -rw-r--r-- 2009-07-01 12:47 +0200 30961 CHANGES.html file | revisions | annotate + -rw-r--r-- 2009-07-01 12:47 +0200 17987 LICENSE file | revisions | annotate + -rw-r--r-- 2009-07-01 12:47 +0200 3742 README file | revisions | annotate + -rw-r--r-- 2009-07-01 12:47 +0200 16171 RELEASE_NOTES file | revisions | annotate + -rw-r--r-- 2009-07-01 12:47 +0200 6 VERSION file | revisions | annotate + -rwxr-xr-x 2009-07-01 12:47 +0200 88110 waf file | revisions | annotate + -rwxr-xr-x 2009-07-01 12:47 +0200 28 waf.bat file | revisions | annotate + -rw-r--r-- 2009-07-01 12:47 +0200 35395 wscript file | revisions | annotate + -rw-r--r-- 2009-07-01 12:47 +0200 7673 wutils.py file | revisions | annotate + +Our example scripts are in the ``examples`` directory. If you click on ``examples`` +you will see a list of files. One of the files in that directory is ``first.cc``. If +you click on ``first.cc`` you will find the code you just walked through. + +The source code is mainly in the ``src`` directory. You can view source +code either by clicking on the directory name or by clicking on the ``files`` +link to the right of the directory name. If you click on the ``src`` +directory, you will be taken to the listing of the ``src`` subdirectories. If you +then click on ``core`` subdirectory, you will find a list of files. The first file +you will find (as of this writing) is ``abort.h``. If you click on the +``abort.h`` link, you will be sent to the source file for ``abort.h`` which +contains useful macros for exiting scripts if abnormal conditions are detected. + +The source code for the helpers we have used in this chapter can be found in the +``src/helper`` directory. Feel free to poke around in the directory tree to +get a feel for what is there and the style of |ns3| programs. diff -r c9133c87760d -r 7ff69b244b5b doc/tutorial/source/conclusion.rst --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/tutorial/source/conclusion.rst Sun Jan 02 22:57:32 2011 -0800 @@ -0,0 +1,37 @@ +.. include:: replace.txt + + +Conclusion +---------- + +Futures +******* + +This document is a work in process. We hope and expect it to grow over time +to cover more and more of the nuts and bolts of |ns3|. + +We hope to add the following chapters over the next few releases: + +* The Callback System +* The Object System and Memory Management +* The Routing System +* Adding a New NetDevice and Channel +* Adding a New Protocol +* Working with Real Networks and Hosts + +Writing manual and tutorial chapters is not something we all get excited about, +but it is very important to the project. If you are an expert in one of these +areas, please consider contributing to |ns3| by providing one of these +chapters; or any other chapter you may think is important. + +Closing +******* + +|ns3| is a large and complicated system. It is impossible to cover all +of the things you will need to know in one small tutorial. + +We have really just scratched the surface of |ns3| in this tutorial, +but we hope to have covered enough to get you started doing useful networking +research using our favorite simulator. + +-- The |ns3| development team. diff -r c9133c87760d -r 7ff69b244b5b doc/tutorial/source/conf.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/tutorial/source/conf.py Sun Jan 02 22:57:32 2011 -0800 @@ -0,0 +1,216 @@ +# -*- coding: utf-8 -*- +# +# ns-3 documentation build configuration file, created by +# sphinx-quickstart on Tue Dec 14 09:00:39 2010. +# +# This file is execfile()d with the current directory set to its containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +import sys, os + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +#sys.path.insert(0, os.path.abspath('.')) + +# -- General configuration ----------------------------------------------------- + +# If your documentation needs a minimal Sphinx version, state it here. +#needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be extensions +# coming with Sphinx (named 'sphinx.ext.*') or your custom ones. +extensions = ['sphinx.ext.pngmath'] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix of source filenames. +source_suffix = '.rst' + +# The encoding of source files. +#source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = u'ns-3' +copyright = u'2010, ns-3 project' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +version = 'ns-3.10' +# The full version, including alpha/beta/rc tags. +release = 'ns-3.10' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +#language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +#today = '' +# Else, today_fmt is used as the format for a strftime call. +#today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = [] + +# The reST default role (used for this markup: `text`) to use for all documents. +#default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +#add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +#add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +#show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# A list of ignored prefixes for module index sorting. +#modindex_common_prefix = [] + + +# -- Options for HTML output --------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +html_theme = 'default' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +#html_theme_options = {} + +# Add any paths that contain custom themes here, relative to this directory. +#html_theme_path = [] + +# The name for this set of Sphinx documents. If None, it defaults to +# " v documentation". +#html_title = None + +# A shorter title for the navigation bar. Default is the same as html_title. +#html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +#html_logo = None + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +#html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +#html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +#html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +#html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +#html_additional_pages = {} + +# If false, no module index is generated. +#html_domain_indices = True + +# If false, no index is generated. +#html_use_index = True + +# If true, the index is split into individual pages for each letter. +#html_split_index = False + +# If true, links to the reST sources are added to the pages. +#html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +#html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +#html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +#html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = None + +# Output file base name for HTML help builder. +htmlhelp_basename = 'ns-3doc' + + +# -- Options for LaTeX output -------------------------------------------------- + +# The paper size ('letter' or 'a4'). +#latex_paper_size = 'letter' + +# The font size ('10pt', '11pt' or '12pt'). +#latex_font_size = '10pt' + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, author, documentclass [howto/manual]). +latex_documents = [ + ('index', 'ns-3.tex', u'ns-3 Tutorial', + u'ns-3 project', 'manual'), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +#latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +#latex_use_parts = False + +# If true, show page references after internal links. +#latex_show_pagerefs = False + +# If true, show URL addresses after external links. +#latex_show_urls = False + +# Additional stuff for the LaTeX preamble. +#latex_preamble = '' + +# Documents to append as an appendix to all manuals. +#latex_appendices = [] + +# If false, no module index is generated. +#latex_domain_indices = True + + +# -- Options for manual page output -------------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + ('index', 'ns-3', u'ns-3 Tutorial', + [u'ns-3 project'], 1) +] diff -r c9133c87760d -r 7ff69b244b5b doc/tutorial/source/figures --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/tutorial/source/figures Sun Jan 02 22:57:32 2011 -0800 @@ -0,0 +1,1 @@ +../figures \ No newline at end of file diff -r c9133c87760d -r 7ff69b244b5b doc/tutorial/source/getting-started.rst --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/tutorial/source/getting-started.rst Sun Jan 02 22:57:32 2011 -0800 @@ -0,0 +1,512 @@ + .. include:: replace.txt + + +Getting Started +--------------- + +Downloading ns-3 +**************** + +The |ns3| system as a whole is a fairly complex system and has a +number of dependencies on other components. Along with the systems you will +most likely deal with every day (the GNU toolchain, Mercurial, you programmer +editor) you will need to ensure that a number of additional libraries are +present on your system before proceeding. |ns3| provides a wiki +for your reading pleasure that includes pages with many useful hints and tips. +One such page is the "Installation" page, +http://www.nsnam.org/wiki/index.php/Installation. + +The "Prerequisites" section of this wiki page explains which packages are +required to support common |ns3| options, and also provides the +commands used to install them for common Linux variants. Cygwin users will +have to use the Cygwin installer (if you are a Cygwin user, you used it to +install Cygwin). + +You may want to take this opportunity to explore the |ns3| wiki +a bit since there really is a wealth of information there. + +From this point forward, we are going to assume that the reader is working in +Linux or a Linux emulation environment (Linux, Cygwin, etc.) and has the GNU +toolchain installed and verified along with the prerequisites mentioned +above. We are also going to assume that you have Mercurial and Waf installed +and running on the target system as described in the "Getting Started" section +of the |ns3| web site: +http://www.nsnam.org/getting_started.html. + +The |ns3| code is available in Mercurial repositories on the server +http://code.nsnam.org. You can also download a tarball release at +http://www.nsnam.org/releases/, or you can work with repositories +using Mercurial. We recommend using Mercurial unless there's a good reason +not to. See the end of this section for instructions on how to get a tarball +release. + +The simplest way to get started using Mercurial repositories is to use the +``ns-3-allinone`` environment. This is a set of scripts that manages the +downloading and building of various subsystems of |ns3| for you. We +recommend that you begin your |ns3| adventures in this environment +as it can really simplify your life at this point. + +Downloading ns-3 Using Mercurial +++++++++++++++++++++++++++++++++ +One practice is to create a directory called ``repos`` in one's home +directory under which one can keep local Mercurial repositories. +*Hint: we will assume you do this later in the tutorial.* If you adopt +that approach, you can get a copy of ``ns-3-allinone`` by typing the +following into your Linux shell (assuming you have installed Mercurial): + +:: + + cd + mkdir repos + cd repos + hg clone http://code.nsnam.org/ns-3-allinone + +As the hg (Mercurial) command executes, you should see something like the +following displayed, + +:: + + destination directory: ns-3-allinone + requesting all changes + adding changesets + adding manifests + adding file changes + added 31 changesets with 45 changes to 7 files + 7 files updated, 0 files merged, 0 files removed, 0 files unresolved + +After the clone command completes, you should have a directory called +``ns-3-allinone`` under your ``~/repos`` directory, the contents of which should +look something like the following: + +:: + + build.py* constants.py dist.py* download.py* README util.py + +Notice that you really just downloaded some Python scripts. The next step +will be to use those scripts to download and build the |ns3| +distribution of your choice. + +If you go to the following link: http://code.nsnam.org/, +you will see a number of repositories. Many are the private repositories of +the |ns3| development team. The repositories of interest to you will +be prefixed with "ns-3". Official releases of |ns3| will be +numbered as ``ns-3..``. For example, a second hotfix to a +still hypothetical release nine of |ns3| would be numbered as +``ns-3.9.2``. + +The current development snapshot (unreleased) of |ns3| may be found +at http://code.nsnam.org/ns-3-dev/. The +developers attempt to keep these repository in consistent, working states but +they are in a development area with unreleased code present, so you may want +to consider staying with an official release if you do not need newly- +introduced features. + +Since the release numbers are going to be changing, I will stick with +the more constant ns-3-dev here in the tutorial, but you can replace the +string "ns-3-dev" with your choice of release (e.g., ns-3.10) in the +text below. You can find the latest version of the +code either by inspection of the repository list or by going to the +`"Getting Started" +`_ +web page and looking for the latest release identifier. + +Go ahead and change into the ``ns-3-allinone`` directory you created when +you cloned that repository. We are now going to use the ``download.py`` +script to pull down the various pieces of |ns3| you will be using. + +Go ahead and type the following into your shell (remember you can substitute +the name of your chosen release number instead of ``ns-3-dev`` -- like +``"ns-3.10"`` if you want to work with a +stable release). + +:: + + ./download.py -n ns-3-dev + +Note that the default for the ``-n`` option is ``ns-3-dev`` and so the +above is actually redundant. We provide this example to illustrate how to +specify alternate repositories. In order to download ``ns-3-dev`` you +can actually use the defaults and simply type, + +:: + + ./download.py + +As the hg (Mercurial) command executes, you should see something like the +following, + +:: + + # + # Get NS-3 + # + + Cloning ns-3 branch + => hg clone http://code.nsnam.org/ns-3-dev ns-3-dev + requesting all changes + adding changesets + adding manifests + adding file changes + added 4634 changesets with 16500 changes to 1762 files + 870 files updated, 0 files merged, 0 files removed, 0 files unresolved + +This is output by the download script as it fetches the actual ``ns-3`` +code from the repository. + +The download script is smart enough to know that on some platforms various +pieces of ns-3 are not supported. On your platform you may not see some +of these pieces come down. However, on most platforms, the process should +continue with something like, + +:: + + # + # Get PyBindGen + # + + Required pybindgen version: 0.10.0.640 + Trying to fetch pybindgen; this will fail if no network connection is available. Hit Ctrl-C to skip. + => bzr checkout -rrevno:640 https://launchpad.net/pybindgen pybindgen + Fetch was successful. + +This was the download script getting the Python bindings generator for you. +Note that you will need bazaar (bzr), a version control system, to download +PyBindGen. Next you should see (modulo platform variations) something along +the lines of, + +:: + + # + # Get NSC + # + + Required NSC version: nsc-0.5.0 + Retrieving nsc from https://secure.wand.net.nz/mercurial/nsc + => hg clone https://secure.wand.net.nz/mercurial/nsc nsc + requesting all changes + adding changesets + adding manifests + adding file changes + added 273 changesets with 17565 changes to 15175 files + 10622 files updated, 0 files merged, 0 files removed, 0 files unresolved + +This part of the process is the script downloading the Network Simulation +Cradle for you. Note that NSC is not supported on OSX or Cygwin and works +best with gcc-3.4 or gcc-4.2 or greater series. + +After the download.py script completes, you should have several new directories +under ``~/repos/ns-3-allinone``: + +:: + + build.py* constants.pyc download.py* nsc/ README util.pyc + constants.py dist.py* ns-3-dev/ pybindgen/ util.py + +Go ahead and change into ``ns-3-dev`` under your ``~/repos/ns-3-allinone`` +directory. You should see something like the following there: + +:: + + AUTHORS examples/ RELEASE_NOTES utils/ wscript + bindings/ LICENSE samples/ VERSION wutils.py + CHANGES.html ns3/ scratch/ waf* + doc/ README src/ waf.bat* + +You are now ready to build the |ns3| distribution. + +Downloading ns-3 Using a Tarball +++++++++++++++++++++++++++++++++ +The process for downloading |ns3| via tarball is simpler than the +Mercurial process since all of the pieces are pre-packaged for you. You just +have to pick a release, download it and decompress it. + +As mentioned above, one practice is to create a directory called ``repos`` +in one's home directory under which one can keep local Mercurial repositories. +One could also keep a ``tarballs`` directory. *Hint: the tutorial +will assume you downloaded into a ``repos`` directory, so remember the +placekeeper.``* If you adopt the ``tarballs`` directory approach, you can +get a copy of a release by typing the following into your Linux shell +(substitute the appropriate version numbers, of course): + +:: + + cd + mkdir tarballs + cd tarballs + wget http://www.nsnam.org/releases/ns-allinone-3.10.tar.bz2 + tar xjf ns-allinone-3.10.tar.bz2 + +If you change into the directory ``ns-allinone-3.10`` you should see a +number of files: + +:: + + build.py ns-3.10/ pybindgen-0.15.0/ util.py + constants.py nsc-0.5.2/ README + +You are now ready to build the |ns3| distribution. + +Building ns-3 +************* + +Building with build.py +++++++++++++++++++++++ +The first time you build the |ns3| project you should build using the +``allinone`` environment. This will get the project configured for you +in the most commonly useful way. + +Change into the directory you created in the download section above. If you +downloaded using Mercurial you should have a directory called +``ns-3-allinone`` under your ``~/repos`` directory. If you downloaded +using a tarball you should have a directory called something like +``ns-allinone-3.10`` under your ``~/tarballs`` directory. Take a deep +breath and type the following: + +:: + + ./build.py + +You will see lots of typical compiler output messages displayed as the build +script builds the various pieces you downloaded. Eventually you should see the +following magic words: + +:: + + Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' + 'build' finished successfully (2m30.586s) + +Once the project has built you can say goodbye to your old friends, the +``ns-3-allinone`` scripts. You got what you needed from them and will now +interact directly with Waf and we do it in the ``ns-3-dev`` directory, +not in the ``ns-3-allinone`` directory. Go ahead and change into the +``ns-3-dev`` directory (or the directory for the appropriate release you +downloaded. + +:: + + cd ns-3-dev + +Building with Waf ++++++++++++++++++ +We use Waf to configure and build the |ns3| project. It's not +strictly required at this point, but it will be valuable to take a slight +detour and look at how to make changes to the configuration of the project. +Probably the most useful configuration change you can make will be to +build the optimized version of the code. By default you have configured +your project to build the debug version. Let's tell the project to do +make an optimized build. To explain to Waf that it should do optimized +builds you will need to execute the following command, + +:: + + ./waf -d optimized configure + +This runs Waf out of the local directory (which is provided as a convenience +for you). As the build system checks for various dependencies you should see +output that looks similar to the following, + +:: + + Checking for program g++ : ok /usr/bin/g++ + Checking for program cpp : ok /usr/bin/cpp + Checking for program ar : ok /usr/bin/ar + Checking for program ranlib : ok /usr/bin/ranlib + Checking for g++ : ok + Checking for program pkg-config : ok /usr/bin/pkg-config + Checking for -Wno-error=deprecated-declarations support : yes + Checking for -Wl,--soname=foo support : yes + Checking for header stdlib.h : ok + Checking for header signal.h : ok + Checking for header pthread.h : ok + Checking for high precision time implementation : 128-bit integer + Checking for header stdint.h : ok + Checking for header inttypes.h : ok + Checking for header sys/inttypes.h : not found + Checking for library rt : ok + Checking for header netpacket/packet.h : ok + Checking for pkg-config flags for GSL : ok + Checking for header linux/if_tun.h : ok + Checking for pkg-config flags for GTK_CONFIG_STORE : ok + Checking for pkg-config flags for LIBXML2 : ok + Checking for library sqlite3 : ok + Checking for NSC location : ok ../nsc (guessed) + Checking for library dl : ok + Checking for NSC supported architecture x86_64 : ok + Checking for program python : ok /usr/bin/python + Checking for Python version >= 2.3 : ok 2.5.2 + Checking for library python2.5 : ok + Checking for program python2.5-config : ok /usr/bin/python2.5-config + Checking for header Python.h : ok + Checking for -fvisibility=hidden support : yes + Checking for pybindgen location : ok ../pybindgen (guessed) + Checking for Python module pybindgen : ok + Checking for pybindgen version : ok 0.10.0.640 + Checking for Python module pygccxml : ok + Checking for pygccxml version : ok 0.9.5 + Checking for program gccxml : ok /usr/local/bin/gccxml + Checking for gccxml version : ok 0.9.0 + Checking for program sudo : ok /usr/bin/sudo + Checking for program hg : ok /usr/bin/hg + Checking for program valgrind : ok /usr/bin/valgrind + ---- Summary of optional NS-3 features: + Threading Primitives : enabled + Real Time Simulator : enabled + Emulated Net Device : enabled + GNU Scientific Library (GSL) : enabled + Tap Bridge : enabled + GtkConfigStore : enabled + XmlIo : enabled + SQlite stats data output : enabled + Network Simulation Cradle : enabled + Python Bindings : enabled + Python API Scanning Support : enabled + Use sudo to set suid bit : not enabled (option --enable-sudo not selected) + Build examples and samples : enabled + Static build : not enabled (option --enable-static not selected) + 'configure' finished successfully (2.870s) + +Note the last part of the above output. Some ns-3 options are not enabled by +default or require support from the underlying system to work properly. +For instance, to enable XmlTo, the library libxml-2.0 must be found on the +system. If this library were not found, the corresponding |ns3| feature +would not be enabled and a message would be displayed. Note further that there is +a feature to use the program ``sudo`` to set the suid bit of certain programs. +This is not enabled by default and so this feature is reported as "not enabled." + +Now go ahead and switch back to the debug build. + +:: + + ./waf -d debug configure + +The build system is now configured and you can build the debug versions of +the |ns3| programs by simply typing, + +:: + + ./waf + +Some waf commands are meaningful during the build phase and some commands are valid +in the configuration phase. For example, if you wanted to use the emulation +features of |ns3| you might want to enable setting the suid bit using +sudo as described above. This turns out to be a configuration-time command, and so +you could reconfigure using the following command + +:: + + ./waf -d debug --enable-sudo configure + +If you do this, waf will have run sudo to change the socket creator programs of the +emulation code to run as root. There are many other configure- and build-time options +available in waf. To explore these options, type: + +:: + + ./waf --help + +We'll use some of the testing-related commands in the next section. + +Okay, sorry, I made you build the |ns3| part of the system twice, +but now you know how to change the configuration and build optimized code. + +Testing ns-3 +************ + +You can run the unit tests of the |ns3| distribution by running the +"./test.py -c core" script, + +:: + + ./test.py -c core + +These tests are run in parallel by waf. You should eventually +see a report saying that, + +:: + + 47 of 47 tests passed (47 passed, 0 failed, 0 crashed, 0 valgrind errors) + +This is the important message. + +You will also see output from the test runner and the output will actually look something like, + +:: + + Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' + Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' + 'build' finished successfully (1.799s) + PASS: TestSuite ns3-wifi-interference + PASS: TestSuite histogram + PASS: TestSuite sample + PASS: TestSuite ipv4-address-helper + PASS: TestSuite devices-wifi + PASS: TestSuite propagation-loss-model + + ... + + PASS: TestSuite attributes + PASS: TestSuite config + PASS: TestSuite global-value + PASS: TestSuite command-line + PASS: TestSuite basic-random-number + PASS: TestSuite object + PASS: TestSuite random-number-generators + 47 of 47 tests passed (47 passed, 0 failed, 0 crashed, 0 valgrind errors) + +This command is typically run by ``users`` to quickly verify that an +|ns3| distribution has built correctly. + +Running a Script +**************** +We typically run scripts under the control of Waf. This allows the build +system to ensure that the shared library paths are set correctly and that +the libraries are available at run time. To run a program, simply use the +``--run`` option in Waf. Let's run the |ns3| equivalent of the +ubiquitous hello world program by typing the following: + +:: + + ./waf --run hello-simulator + +Waf first checks to make sure that the program is built correctly and +executes a build if required. Waf then executes the program, which +produces the following output. + +:: + + Hello Simulator + +*Congratulations. You are now an ns-3 user.* + +*What do I do if I don't see the output?* + +If you don't see ``waf`` messages indicating that the build was +completed successfully, but do not see the "Hello Simulator" output, +chances are that you have switched your build mode to "optimized" in +the "Building with Waf" section, but have missed the change back to +"debug" mode. All of the console output used in this tutorial uses a +special |ns3| logging component that is useful for printing +user messages to the console. Output from this component is +automatically disabled when you compile optimized code -- it is +"optimized out." If you don't see the "Hello Simulator" output, +type the following, + +:: + + ./waf -d debug configure + +to tell ``waf`` to build the debug versions of the |ns3| +programs. You must still build the actual debug version of the code by +typing, + +:: + + ./waf + +Now, if you run the ``hello-simulator`` program, you should see the +expected output. + +If you want to run programs under another tool such as gdb or valgrind, +see this `wiki entry +`_. + diff -r c9133c87760d -r 7ff69b244b5b doc/tutorial/source/index.rst --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/tutorial/source/index.rst Sun Jan 02 22:57:32 2011 -0800 @@ -0,0 +1,18 @@ +.. only:: html or latex + + Welcome to ns-3's tutorial! + ================================ + + Contents: + +.. toctree:: + :maxdepth: 2 + + introduction + resources + getting-started + conceptual-overview + tweaking + building-topologies + tracing + conclusion diff -r c9133c87760d -r 7ff69b244b5b doc/tutorial/source/introduction.rst --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/tutorial/source/introduction.rst Sun Jan 02 22:57:32 2011 -0800 @@ -0,0 +1,125 @@ +.. include:: replace.txt + +Introduction +------------ + +The |ns3| simulator is a discrete-event network simulator targeted +primarily for research and educational use. The +`ns-3 project +`_, +started in 2006, is an open-source project developing |ns3|. + +Primary documentation for the |ns3| project is available in four +forms: + +* `ns-3 Doxygen/Manual + `_: + Documentation of the public APIs of the simulator +* Tutorial (this document) +* `Reference Manual + `_: Reference Manual +* `ns-3 wiki + `_ + +The purpose of this tutorial is to introduce new |ns3| users to the +system in a structured way. It is sometimes difficult for new users to +glean essential information from detailed manuals and to convert this +information into working simulations. In this tutorial, we will build +several example simulations, introducing and explaining key concepts and +features as we go. + +As the tutorial unfolds, we will introduce the full |ns3| documentation +and provide pointers to source code for those interested in delving deeper +into the workings of the system. + +A few key points are worth noting at the onset: + +* Ns-3 is not an extension of `ns-2 + `_; + it is a new simulator. The two simulators are both written in C++ but + |ns3| is a new simulator that does not support the ns-2 APIs. Some + models from ns-2 have already been ported from ns-2 to |ns3|. The + project will continue to maintain ns-2 while |ns3| is being built, + and will study transition and integration mechanisms. +* |ns3| is open-source, and the project strives to maintain an + open environment for researchers to contribute and share their software. + + +For ns-2 Users +************** + +For those familiar with ns-2, the most visible outward change when moving to +|ns3| is the choice of scripting language. Ns-2 is +scripted in OTcl and results of simulations can be visualized using the +Network Animator nam. It is not possible to run a simulation +in ns-2 purely from C++ (i.e., as a main() program without any OTcl). +Moreover, some components of ns-2 are written in C++ and others in OTcl. +In |ns3|, the simulator is written entirely in C++, with optional +Python bindings. Simulation scripts can therefore be written in C++ +or in Python. The results of some simulations can be visualized by +nam, but new animators are under development. Since |ns3| +generates pcap packet trace files, other utilities can be used to +analyze traces as well. +In this tutorial, we will first concentrate on scripting +directly in C++ and interpreting results via trace files. + +But there are similarities as well (both, for example, are based on C++ +objects, and some code from ns-2 has already been ported to |ns3|). +We will try to highlight differences between ns-2 and |ns3| +as we proceed in this tutorial. + +A question that we often hear is "Should I still use ns-2 or move to +|ns3|?" The answer is that it depends. |ns3| does not have +all of the models that ns-2 currently has, but on the other hand, |ns3| +does have new capabilities (such as handling multiple interfaces on nodes +correctly, use of IP addressing and more alignment with Internet +protocols and designs, more detailed 802.11 models, etc.). ns-2 +models can usually be ported to |ns3| (a porting guide is under +development). There is active development on multiple fronts for +|ns3|. The |ns3| developers believe (and certain early users +have proven) that |ns3| is ready for active use, and should be an +attractive alternative for users looking to start new simulation projects. + +Contributing +************ + +|ns3| is a research and educational simulator, by and for the +research community. It will rely on the ongoing contributions of the +community to develop new models, debug or maintain existing ones, and share +results. There are a few policies that we hope will encourage people to +contribute to |ns3| like they have for ns-2: + +* Open source licensing based on GNU GPLv2 compatibility; +* `wiki + `_; +* `Contributed Code + `_ page, similar to ns-2's popular Contributed Code + `page + `_; +* ``src/contrib`` directory (we will host your contributed code); +* Open `bug tracker + `_; +* |ns3| developers will gladly help potential contributors to get + started with the simulator (please contact `one of us + `_). + +We realize that if you are reading this document, contributing back to +the project is probably not your foremost concern at this point, but +we want you to be aware that contributing is in the spirit of the project and +that even the act of dropping us a note about your early experience +with |ns3| (e.g. "this tutorial section was not clear..."), +reports of stale documentation, etc. are much appreciated. + +Tutorial Organization +********************* + +The tutorial assumes that new users might initially follow a path such as the +following: + +* Try to download and build a copy; +* Try to run a few sample programs; +* Look at simulation output, and try to adjust it. + +As a result, we have tried to organize the tutorial along the above +broad sequences of events. + diff -r c9133c87760d -r 7ff69b244b5b doc/tutorial/source/replace.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/tutorial/source/replace.txt Sun Jan 02 22:57:32 2011 -0800 @@ -0,0 +1,3 @@ +.. |ns3| replace:: *ns-3* + +.. |ns2| replace:: *ns-2* diff -r c9133c87760d -r 7ff69b244b5b doc/tutorial/source/resources.rst --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/tutorial/source/resources.rst Sun Jan 02 22:57:32 2011 -0800 @@ -0,0 +1,144 @@ +.. include:: replace.txt + +Resources +--------- + +The Web +******* + +There are several important resources of which any |ns3| user must be +aware. The main web site is located at http://www.nsnam.org and +provides access to basic information about the |ns3| system. Detailed +documentation is available through the main web site at +http://www.nsnam.org/documents.html. You can also find documents +relating to the system architecture from this page. + +There is a Wiki that complements the main |ns3| web site which you will +find at http://www.nsnam.org/wiki/. You will find user and developer +FAQs there, as well as troubleshooting guides, third-party contributed code, +papers, etc. + +The source code may be found and browsed at http://code.nsnam.org/. +There you will find the current development tree in the repository named +``ns-3-dev``. Past releases and experimental repositories of the core +developers may also be found there. + +Mercurial +********* + +Complex software systems need some way to manage the organization and +changes to the underlying code and documentation. There are many ways to +perform this feat, and you may have heard of some of the systems that are +currently used to do this. The Concurrent Version System (CVS) is probably +the most well known. + +The |ns3| project uses Mercurial as its source code management system. +Although you do not need to know much about Mercurial in order to complete +this tutorial, we recommend becoming familiar with Mercurial and using it +to access the source code. Mercurial has a web site at +http://www.selenic.com/mercurial/, +from which you can get binary or source releases of this Software +Configuration Management (SCM) system. Selenic (the developer of Mercurial) +also provides a tutorial at +http://www.selenic.com/mercurial/wiki/index.cgi/Tutorial/, +and a QuickStart guide at +http://www.selenic.com/mercurial/wiki/index.cgi/QuickStart/. + +You can also find vital information about using Mercurial and |ns3| +on the main |ns3| web site. + +Waf +*** + +Once you have source code downloaded to your local system, you will need +to compile that source to produce usable programs. Just as in the case of +source code management, there are many tools available to perform this +function. Probably the most well known of these tools is ``make``. Along +with being the most well known, ``make`` is probably the most difficult to +use in a very large and highly configurable system. Because of this, many +alternatives have been developed. Recently these systems have been developed +using the Python language. + +The build system Waf is used on the |ns3| project. It is one +of the new generation of Python-based build systems. You will not need to +understand any Python to build the existing |ns3| system, and will +only have to understand a tiny and intuitively obvious subset of Python in +order to extend the system in most cases. + +For those interested in the gory details of Waf, the main web site can be +found at http://code.google.com/p/waf/. + +Development Environment +*********************** + +As mentioned above, scripting in |ns3| is done in C++ or Python. +As of ns-3.2, most of the |ns3| API is available in Python, but the +models are written in C++ in either case. A working +knowledge of C++ and object-oriented concepts is assumed in this document. +We will take some time to review some of the more advanced concepts or +possibly unfamiliar language features, idioms and design patterns as they +appear. We don't want this tutorial to devolve into a C++ tutorial, though, +so we do expect a basic command of the language. There are an almost +unimaginable number of sources of information on C++ available on the web or +in print. + +If you are new to C++, you may want to find a tutorial- or cookbook-based +book or web site and work through at least the basic features of the language +before proceeding. For instance, `this tutorial +`_. + +The |ns3| system uses several components of the GNU "toolchain" +for development. A +software toolchain is the set of programming tools available in the given +environment. For a quick review of what is included in the GNU toolchain see, +http://en.wikipedia.org/wiki/GNU_toolchain. |ns3| uses gcc, +GNU binutils, and gdb. However, we do not use the GNU build system tools, +neither make nor autotools. We use Waf for these functions. + +Typically an |ns3| author will work in Linux or a Linux-like +environment. For those running under Windows, there do exist environments +which simulate the Linux environment to various degrees. The |ns3| +project supports development in the Cygwin environment for +these users. See http://www.cygwin.com/ +for details on downloading (MinGW is presently not officially supported, +although some of the project maintainers to work with it). Cygwin provides +many of the popular Linux system commands. It can, however, sometimes be +problematic due to the way it actually does its emulation, and sometimes +interactions with other Windows software can cause problems. + +If you do use Cygwin or MinGW; and use Logitech products, we will save you +quite a bit of heartburn right off the bat and encourage you to take a look +at the `MinGW FAQ +`_. + +Search for "Logitech" and read the FAQ entry, "why does make often +crash creating a sh.exe.stackdump file when I try to compile my source code." +Believe it or not, the ``Logitech Process Monitor`` insinuates itself into +every DLL in the system when it is running. It can cause your Cygwin or +MinGW DLLs to die in mysterious ways and often prevents debuggers from +running. Beware of Logitech software when using Cygwin. + +Another alternative to Cygwin is to install a virtual machine environment +such as VMware server and install a Linux virtual machine. + +Socket Programming +****************** + +We will assume a basic facility with the Berkeley Sockets API in the examples +used in this tutorial. If you are new to sockets, we recommend reviewing the +API and some common usage cases. For a good overview of programming TCP/IP +sockets we recommend `TCP/IP Sockets in C, Donahoo and Calvert +`_. + +There is an associated web site that includes source for the examples in the +book, which you can find at: +http://cs.baylor.edu/~donahoo/practical/CSockets/. + +If you understand the first four chapters of the book (or for those who do +not have access to a copy of the book, the echo clients and servers shown in +the website above) you will be in good shape to understand the tutorial. +There is a similar book on Multicast Sockets, +`Multicast Sockets, Makofske and Almeroth +`_. +that covers material you may need to understand if you look at the multicast +examples in the distribution. diff -r c9133c87760d -r 7ff69b244b5b doc/tutorial/source/tracing.rst --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/tutorial/source/tracing.rst Sun Jan 02 22:57:32 2011 -0800 @@ -0,0 +1,3179 @@ +.. include:: replace.txt + + +Tracing +------- + +Background +********** + +As mentioned in the Using the Tracing System section, the whole point of running +an |ns3| simulation is to generate output for study. You have two basic +strategies to work with in |ns3|: 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 |ns3|, 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 |ns3| mechanisms, +you may get your code added as a contribution. + +|ns3| 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 |ns3| 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 |ns3|. + +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, + +:: + + #include + ... + void + SomeFunction (void) + { + uint32_t x = SOME_INTERESTING_VALUE; + ... + std::cout << "The value of x is " << x << std::endl; + ... + } + +Nobody is going to prevent you from going deep into the core of |ns3| and +adding print statements. This is insanely easy to do and, after all, you have +complete control of your own |ns3| 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 ``NS_LOG`` +mechanism. In order to avoid that, one of the first things you might consider +is using ``NS_LOG`` itself. + +We mentioned above that one way to get information out of |ns3| 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 |ns3| and simply add your interesting information +to the output stream. Now, this is certainly better than adding your own +print statements since it follows |ns3| 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 +|ns3| TCP socket (``tcp-socket-base.cc``) you could just add a new +message down in the implementation. Notice that in TcpSocketBase::ReceivedAck() +there is no log message for the no ack case. You could simply add one, +changing the code from: + +:: + + /** Process the newly received ACK */ + void + TcpSocketBase::ReceivedAck (Ptr packet, const TcpHeader& tcpHeader) + { + NS_LOG_FUNCTION (this << tcpHeader); + + // Received ACK. Compare the ACK number against highest unacked seqno + if (0 == (tcpHeader.GetFlags () & TcpHeader::ACK)) + { // Ignore if no ACK flag + } + ... + +to add a new ``NS_LOG_LOGIC`` in the appropriate statement: + +:: + + /** Process the newly received ACK */ + void + TcpSocketBase::ReceivedAck (Ptr packet, const TcpHeader& tcpHeader) + { + NS_LOG_FUNCTION (this << tcpHeader); + + // Received ACK. Compare the ACK number against highest unacked seqno + if (0 == (tcpHeader.GetFlags () & TcpHeader::ACK)) + { // Ignore if no ACK flag + NS_LOG_LOGIC ("TcpSocketBase " << this << " no ACK flag"); + } + ... + +This may seem fairly simple and satisfying at first glance, but something to +consider is that you will be writing code to add the ``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 |ns3| about the stability of ``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 ``std::cout`` and NS_LOG messages +to be quick and dirty ways to get more information out of |ns3|. + +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 |ns3| 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. + +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 |ns3| core. + +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. + +Callbacks +~~~~~~~~~ + +The goal of the Callback system in |ns3| 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, + +:: + + int (*pfi)(int arg) = 0; + +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, + +:: + + int MyFunction (int arg) {} + +If you have this target, you can initialize the variable to point to your +function: + +:: + + pfi = MyFunction; + +You can then call MyFunction indirectly using the more suggestive form of +the call, + +:: + + int result = (*pfi) (1234); + +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, + +:: + + int result = pfi (1234); + +This looks like you are calling a function named "pfi," but the compiler is +smart enough to know to call through the variable ``pfi`` indirectly to +the function ``MyFunction``. + +Conceptually, this is almost exactly how the tracing system will work. +Basically, a trace source *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 ``operator()`` providing zero or more parameters. +The ``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 +``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 +|ns3|, feel free to peruse the Callback section of the manual. + +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 ``fourth.cc``. Let's walk through it. + +:: + + /* -*- 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 + + using namespace ns3; + +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, ``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 |ns3| ``Object`` for the trace source +to live in. The next code snippet declares and defines a simple Object we can +work with. + +:: + + class MyObject : public Object + { + public: + static TypeId GetTypeId (void) + { + static TypeId tid = TypeId ("MyObject") + .SetParent (Object::GetTypeId ()) + .AddConstructor () + .AddTraceSource ("MyInteger", + "An integer value to trace.", + MakeTraceSourceAccessor (&MyObject::m_myInt)) + ; + return tid; + } + + MyObject () {} + TracedValue m_myInt; + }; + +The two important lines of code, above, with respect to tracing are the +``.AddTraceSource`` and the ``TracedValue`` declaration of ``m_myInt``. + +The ``.AddTraceSource`` provides the "hooks" used for connecting the trace +source to the outside world through the config system. The ``TracedValue`` +declaration provides the infrastructure that overloads the operators mentioned +above and drives the callback process. + +:: + + void + IntTrace (int32_t oldValue, int32_t newValue) + { + std::cout << "Traced " << oldValue << " to " << newValue << std::endl; + } + +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 ``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. + +:: + + int + main (int argc, char *argv[]) + { + Ptr myObject = CreateObject (); + myObject->TraceConnectWithoutContext ("MyInteger", MakeCallback(&IntTrace)); + + myObject->m_myInt = 1234; + } + +Here we first create the Object in which the trace source lives. + +The next step, the ``TraceConnectWithoutContext``, forms the connection +between the trace source and the trace sink. Notice the ``MakeCallback`` +template function. This function does the magic required to create the +underlying |ns3| Callback object and associate it with the function +``IntTrace``. TraceConnect makes the association between your provided +function and the overloaded ``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 ``pfi()`` +example above to be called by the trace source. The declaration of the +``TracedValue m_myInt;`` in the Object itself performs the magic +needed to provide the overloaded operators (++, ---, etc.) that will use the +``operator()`` to actually invoke the Callback with the desired parameters. +The ``.AddTraceSource`` performs the magic to connect the Callback to the +Config system, and ``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, + +:: + + myObject->m_myInt = 1234; + +should be interpreted as an invocation of ``operator=`` on the member +variable ``m_myInt`` with the integer ``1234`` passed as a parameter. + +It turns out that this operator is defined (by ``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 --- ``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, + +:: + + ./waf --run fourth + +you will see the output from the ``IntTrace`` function execute as soon as the +trace source is hit: + +:: + + Traced 0 to 1234 + +When we executed the code, ``myObject->m_myInt = 1234;``, the trace source +fired and automatically provided the before and after values to the trace sink. +The function ``IntTrace`` then printed this to the standard output. No +problem. + +Using the Config Subsystem to Connect to Trace Sources +++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +The ``TraceConnectWithoutContext`` call shown above in the simple example is +actually very rarely used in the system. More typically, the ``Config`` +subsystem is used to allow selecting a trace source in the system using what is +called a *config path*. We saw an example of this in the previous section +where we hooked the "CourseChange" event when we were playing with +``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. + +:: + + void + CourseChange (std::string context, Ptr model) + { + Vector position = model->GetPosition (); + NS_LOG_UNCOND (context << + " x = " << position.x << ", y = " << position.y); + } + +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: + +:: + + std::ostringstream oss; + oss << + "/NodeList/" << wifiStaNodes.Get (nWifi - 1)->GetId () << + "/$ns3::MobilityModel/CourseChange"; + + Config::Connect (oss.str (), MakeCallback (&CourseChange)); + +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 ``GetId()`` is "7". In this case, the path +above turns out to be, + +:: + + "/NodeList/7/$ns3::MobilityModel/CourseChange" + +The last segment of a config path must be an ``Attribute`` of an +``Object``. In fact, if you had a pointer to the ``Object`` that has the +"CourseChange" ``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 ``third.cc`` example, the Nodes of +interest are stored in the ``wifiStaNodes`` NodeContainer. In fact, while +putting the path together, we used this container to get a Ptr which we +used to call GetId() on. We could have used this Ptr directly to call +a connect method directly: + +:: + + Ptr theObject = wifiStaNodes.Get (nWifi - 1); + theObject->TraceConnectWithoutContext ("CourseChange", MakeCallback (&CourseChange)); + +In the ``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, + +:: + + Ptr theObject = wifiStaNodes.Get (nWifi - 1); + theObject->TraceConnect ("CourseChange", MakeCallback (&CourseChange)); + +It turns out that the internal code for ``Config::ConnectWithoutContext`` and +``Config::Connect`` actually do find a Ptr and call the appropriate +TraceConnect method at the lowest level. + +The ``Config`` functions take a path that represents a chain of ``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 ``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 ``Attribute`` on the last Object it found while walking the path. The +``Config`` functions then call the appropriate ``TraceConnect`` or +``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 +``Ptr`` and so is a subclass of an ``ns3::Object``. + +As described in the Object Model section of the |ns3| 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 ``GetObject`` call should be made +looking for the type that follows. It turns out that the MobilityHelper used in +``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 as specified by "/NodeList/7" to its +associated mobility model --- which is of type "$ns3::MobilityModel". If you +are familiar with ``GetObject``, we have asked the system to do the following: + +:: + + Ptr mobilityModel = node->GetObject () + +We are now at the last Object in the path, so we turn our attention to the +Attributes of that Object. The ``MobilityModel`` class defines an Attribute +called "CourseChange". You can see this by looking at the source code in +``src/mobility/mobility-model.cc`` and searching for "CourseChange" in your +favorite editor. You should find, + +:: + + .AddTraceSource ("CourseChange", + "The value of the position and/or velocity vector changed", + MakeTraceSourceAccessor (&MobilityModel::m_courseChangeTrace)) + +which should look very familiar at this point. + +If you look for the corresponding declaration of the underlying traced variable +in ``mobility-model.h`` you will find + +:: + + TracedCallback > m_courseChangeTrace; + +The type declaration ``TracedCallback`` identifies ``m_courseChangeTrace`` +as a special list of Callbacks that can be hooked using the Config functions +described above. + +The ``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 ``NotifyCourseChange()``: + +:: + + void + MobilityModel::NotifyCourseChange (void) const + { + m_courseChangeTrace(this); + } + +Derived classes will call into this method whenever they do a course change to +support tracing. This method invokes ``operator()`` on the underlying +``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 ``third.cc`` example we looked at, whenever a course change is +made in one of the ``RandomWalk2dMobilityModel`` instances installed, there +will be a ``NotifyCourseChange()`` call which calls up into the +``MobilityModel`` base class. As seen above, this invokes ``operator()`` +on ``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 ``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 ``third.cc``: + +:: + + /NodeList/7/$ns3::MobilityModel/CourseChange x = 7.27897, y = 2.22677 + +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 ``Config::Connect``. + +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"? + +What Trace Sources are Available? ++++++++++++++++++++++++++++++++++ + +The answer to this question is found in the |ns3| Doxygen. Go to the +|ns3| web site `"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: + +* The list of all trace sources +* The list of all attributes +* The list of all global values + +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 |ns3| core. + +As an example, scroll down to ``ns3::MobilityModel``. You will find +an entry for + +:: + + CourseChange: The value of the position and/or velocity vector changed + +You should recognize this as the trace source we used in the ``third.cc`` +example. Perusing this list will be helpful. + +What String do I use to Connect? +++++++++++++++++++++++++++++++++ + +The easiest way to do this is to grep around in the |ns3| 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: + +:: + + find . -name '*.cc' | xargs grep CourseChange | grep Connect + +and you may find your answer along with working code. For example, in this +case, ``./ns-3-dev/examples/wireless/mixed-wireless.cc`` has something +just waiting for you to use: + +:: + + Config::Connect ("/NodeList/*/$ns3::MobilityModel/CourseChange", + MakeCallback (&CourseChangeCallback)); + +If you cannot find any examples in the distribution, you can find this out +from the |ns3| 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 ``third.cc`` example) an +``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 |ns3|. Scroll down until you see the +entry for ``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 ``GetTypeId`` function. You constructed one +of these in the simple tracing example above: + +:: + + static TypeId GetTypeId (void) + { + static TypeId tid = TypeId ("MyObject") + .SetParent (Object::GetTypeId ()) + .AddConstructor () + .AddTraceSource ("MyInteger", + "An integer value to trace.", + MakeTraceSourceAccessor (&MyObject::m_myInt)) + ; + return tid; + } + +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: + +:: + + This object is accessible through the following paths with Config::Set and Config::Connect: + + /NodeList/[i]/$ns3::MobilityModel/$ns3::RandomWalk2dMobilityModel + +The documentation tells you how to get to the ``RandomWalk2dMobilityModel`` +Object. Compare the string above with the string we actually used in the +example code: + +:: + + "/NodeList/7/$ns3::MobilityModel" + +The difference is due to the fact that two ``GetObject`` calls are implied +in the string found in the documentation. The first, for ``$ns3::MobilityModel`` +will query the aggregation for the base class. The second implied +``GetObject`` call, for ``$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 ``GetTypeId`` doxygen. You will find, + +:: + + 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 + +This is exactly what you need to know. The trace source of interest is found in +``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 ``GetObject`` is not required and +you simply use the path: + +:: + + /NodeList/[i]/$ns3::MobilityModel + +which perfectly matches the example path: + +:: + + /NodeList/7/$ns3::MobilityModel + +What Return Value and Formal Arguments? ++++++++++++++++++++++++++++++++++++++++ + +The easiest way to do this is to grep around in the |ns3| codebase for someone +who has already figured it out, You should always try to copy someone else's +working code. Try something like: + +:: + + find . -name '*.cc' | xargs grep CourseChange | grep Connect + +and you may find your answer along with working code. For example, in this +case, ``./ns-3-dev/examples/wireless/mixed-wireless.cc`` has something +just waiting for you to use. You will find + +:: + + Config::Connect ("/NodeList/*/$ns3::MobilityModel/CourseChange", + MakeCallback (&CourseChangeCallback)); + +as a result of your grep. The ``MakeCallback`` should indicate to you that +there is a callback function there which you can use. Sure enough, there is: + +:: + + static void + CourseChangeCallback (std::string path, Ptr model) + { + ... + } + +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 ``TracedCallback`` can be found +from the template parameter list in the declaration. Recall that for our +current example, this is in ``mobility-model.h``, where we have previously +found: + +:: + + TracedCallback > m_courseChangeTrace; + +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 ``Ptr``. +This tells you that you need a function that returns void and takes a +a ``Ptr``. For example, + +:: + + void + CourseChangeCallback (Ptr model) + { + ... + } + +That's all you need if you want to ``Config::ConnectWithoutContext``. If +you want a context, you need to ``Config::Connect`` and use a Callback +function that takes a string context, then the required argument. + +:: + + void + CourseChangeCallback (std::string path, Ptr model) + { + ... + } + +If you want to ensure that your ``CourseChangeCallback`` is only visible +in your local file, you can add the keyword ``static`` and come up with: + +:: + + static void + CourseChangeCallback (std::string path, Ptr model) + { + ... + } + +which is exactly what we used in the ``third.cc`` example. + +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 |ns3| 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 ``TracedCallback`` and understand it. + +The first thing we need to look at is the declaration of the trace source. +Recall that this is in ``mobility-model.h``, where we have previously +found: + +:: + + TracedCallback > m_courseChangeTrace; + +This declaration is for a template. The template parameter is inside the +angle-brackets, so we are really interested in finding out what that +``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 +|ns3| source, so first change into the ``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: + +:: + + find . -name '*.h' | xargs grep TracedCallback + +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. + +:: + + TracedCallback::TracedCallback () + TracedCallback::ConnectWithoutContext (c ... + TracedCallback::Connect (const CallbackB ... + TracedCallback::DisconnectWithoutContext ... + TracedCallback::Disconnect (const Callba ... + TracedCallback::operator() (void) const ... + TracedCallback::operator() (T1 a1) const ... + TracedCallback::operator() (T1 a1, T2 a2 ... + TracedCallback::operator() (T1 a1, T2 a2 ... + TracedCallback::operator() (T1 a1, T2 a2 ... + TracedCallback::operator() (T1 a1, T2 a2 ... + TracedCallback::operator() (T1 a1, T2 a2 ... + TracedCallback::operator() (T1 a1, T2 a2 ... + +It turns out that all of this comes from the header file +``traced-callback.h`` which sounds very promising. You can then take a +look at ``mobility-model.h`` and see that there is a line which confirms +this hunch: + +:: + + #include "ns3/traced-callback.h" + +Of course, you could have gone at this from the other direction and started +by looking at the includes in ``mobility-model.h`` and noticing the +include of ``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 ``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: + +:: + + 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. + +This should sound very familiar and let you know you are on the right track. + +Just after this comment, you will find, + +:: + + template + class TracedCallback + { + ... + +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: + +:: + + TracedCallback > m_courseChangeTrace; + +The ``typename T1`` in the templated class declaration corresponds to the +``Ptr`` 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 ``Connect`` +and ``ConnectWithoutContext`` functions. If you scroll down, you will see +a ``ConnectWithoutContext`` method here: + +:: + + template + void + TracedCallback::ConnectWithoutContext ... + { + Callback cb; + cb.Assign (callback); + m_callbackList.push_back (cb); + } + +You are now in the belly of the beast. When the template is instantiated for +the declaration above, the compiler will replace ``T1`` with +``Ptr``. + +:: + + void + TracedCallback::ConnectWithoutContext ... cb + { + Callback > cb; + cb.Assign (callback); + m_callbackList.push_back (cb); + } + +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 ``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 ``TracedCallback``, you will be +able to find that the file ``./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: + +:: + + 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. + +We are trying to figure out what the + +:: + + Callback > cb; + +declaration means. Now we are in a position to understand that the first +(non-optional) parameter, ``void``, represents the return type of the +Callback. The second (non-optional) parameter, ``Ptr`` +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 ``void`` and takes +a ``Ptr``. For example, + +:: + + void + CourseChangeCallback (Ptr model) + { + ... + } + +That's all you need if you want to ``Config::ConnectWithoutContext``. If +you want a context, you need to ``Config::Connect`` and use a Callback +function that takes a string context. This is because the ``Connect`` +function will provide the context for you. You'll need: + +:: + + void + CourseChangeCallback (std::string path, Ptr model) + { + ... + } + +If you want to ensure that your ``CourseChangeCallback`` is only visible +in your local file, you can add the keyword ``static`` and come up with: + +:: + + static void + CourseChangeCallback (std::string path, Ptr model) + { + ... + } + +which is exactly what we used in the ``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 |ns3| manual. They are one +of the most frequently used constructs in the low-level parts of |ns3|. +It is, in my opinion, a quite elegant thing. + +What About TracedValue? ++++++++++++++++++++++++ + +Earlier in this section, we presented a simple piece of code that used a +``TracedValue`` to demonstrate the basics of the tracing code. +We just glossed over the way to find the return type and formal arguments +for the ``TracedValue``. Rather than go through the whole exercise, we +will just point you at the correct file, ``src/core/traced-value.h`` and +to the important piece of code: + +:: + + template + 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 m_cb; + }; + +Here you see that the ``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 (``m_v`` in the private section of the +class) will be an ``int32_t m_v``. The ``Set`` method will take a +``const int32_t &v`` as a parameter. You should now be able to understand +that the ``Set`` code will fire the ``m_cb`` callback with two parameters: +the first being the current value of the ``TracedValue``; and the second +being the new value being set. + +The callback, ``m_cb`` is declared as a ``TracedCallback`` which +will correspond to a ``TracedCallback`` when the class is +instantiated. + +Recall that the callback target of a TracedCallback always returns ``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: + +:: + + void + MyCallback (int32_t oldValue, int32_t newValue) + { + ... + } + +It probably won't surprise you that this is exactly what we provided in that +simple example we covered so long ago: + +:: + + void + IntTrace (int32_t oldValue, int32_t newValue) + { + std::cout << "Traced " << oldValue << " to " << newValue << std::endl; + } + +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 |ns3| +using the tracing system and ``gnuplot``. + +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 |ns3| Doxygen in the "Core" Module section. If you scroll +through the list, you will eventually find: + +:: + + ns3::TcpNewReno + CongestionWindow: The TCP connection's congestion window + +It turns out that the |ns3| TCP implementation lives (mostly) in the +file ``src/internet-stack/tcp-socket-base.cc`` while congestion control +variants are in files such as ``src/internet-stack/tcp-newreno.cc``. +If you don't know this a priori, you can use the recursive grep trick: + +:: + + find . -name '*.cc' | xargs grep -i tcp + +You will find page after page of instances of tcp pointing you to that file. + +If you open ``src/internet-stack/tcp-newreno.cc`` in your favorite +editor, you will see right up at the top of the file, the following declarations: + +:: + + TypeId + TcpNewReno::GetTypeId () + { + static TypeId tid = TypeId("ns3::TcpNewReno") + .SetParent () + .AddConstructor () + .AddTraceSource ("CongestionWindow", + "The TCP connection's congestion window", + MakeTraceSourceAccessor (&TcpNewReno::m_cWnd)) + ; + return tid; + } + +This should tell you to look for the declaration of ``m_cWnd`` in the header +file ``src/internet-stack/tcp-newreno.h``. If you open this file in your +favorite editor, you will find: + +:: + + TracedValue m_cWnd; //Congestion window + +You should now understand this code completely. If we have a pointer to the +``TcpNewReno``, we can ``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 ``uint32_t`` instead of ``int32_t``. + +We now know that we need to provide a callback that returns void and takes +two ``uint32_t`` parameters, the first being the old value and the second +being the new value: + +:: + + void + CwndTrace (uint32_t oldValue, uint32_t newValue) + { + ... + } + +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: + +:: + + find . -name '*.cc' | xargs grep CongestionWindow + +This will point out a couple of promising candidates: +``examples/tcp/tcp-large-transfer.cc`` and +``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 ``src/test/ns3tcp/ns3tcp-cwnd-test-suite.cc`` in your +favorite editor and search for "CongestionWindow". You will find, + +:: + + ns3TcpSocket->TraceConnectWithoutContext ("CongestionWindow", + MakeCallback (&Ns3TcpCwndTestCase1::CwndChange, this)); + +This should look very familiar to you. We mentioned above that if we had a +pointer to the ``TcpNewReno``, we could ``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 +(``Ns3TcpCwndTestCase1::DoRun (void)``). If you look at this function, +you will find that it looks just like an |ns3| 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 ``main`` instead of in ``DoRun``. Rather than +walk through this, step, by step, we have provided the file that results from +porting this test back to a native |ns3| script -- +``examples/tutorial/fifth.cc``. + +A Common Problem and Solution ++++++++++++++++++++++++++++++ + +The ``fifth.cc`` example demonstrates an extremely important rule that you +must understand before using any kind of ``Attribute``: you must ensure +that the target of a ``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 |ns3| script. The first time period is sometimes called +"Configuration Time" or "Setup Time," and is in force during the period +when the ``main`` function of your script is running, but before +``Simulator::Run`` is called. The second time period is sometimes called +"Simulation Time" and is in force during the time period when +``Simulator::Run`` is actively executing its events. After it completes +executing the simulation, ``Simulator::Run`` will return control back to +the ``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 |ns3| +``Socket`` is a dynamic object often created by ``Applications`` to +communicate between ``Nodes``. An |ns3| ``Application`` +always has a "Start Time" and a "Stop Time" associated with it. In the +vast majority of cases, an ``Application`` will not attempt to create +a dynamic object until its ``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 ``fifth.cc`` example. This decision required us to create +the ``MyApp`` ``Application``, the entire purpose of which is to take +a ``Socket`` as a parameter. + +A fifth.cc Walkthrough +++++++++++++++++++++++ + +Now, let's take a look at the example program we constructed by dissecting +the congestion window test. Open ``examples/tutorial/fifth.cc`` in your +favorite editor. You should see some familiar looking code: + +:: + + /* -*- 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 + #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"); + +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 ``Socket``. + +:: + + // =========================================================================== + // + // 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. + // =========================================================================== + // + +This should also be self-explanatory. + +The next part is the declaration of the ``MyApp`` ``Application`` that +we put together to allow the ``Socket`` to be created at configuration time. + +:: + + class MyApp : public Application + { + public: + + MyApp (); + virtual ~MyApp(); + + void Setup (Ptr 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 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; + }; + +You can see that this class inherits from the |ns3| ``Application`` +class. Take a look at ``src/node/application.h`` if you are interested in +what is inherited. The ``MyApp`` class is obligated to override the +``StartApplication`` and ``StopApplication`` methods. These methods are +automatically called when ``MyApp`` is required to start and stop sending +data during the simulation. + +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 |ns3| 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 ``Application``. +This is done as the result of the following (hopefully) familar lines of an +|ns3| script: + +:: + + ApplicationContainer apps = ... + apps.Start (Seconds (1.0)); + apps.Stop (Seconds (10.0)); + +The application container code (see ``src/helper/application-container.h`` if +you are interested) loops through its contained applications and calls, + +:: + + app->SetStartTime (startTime); + +as a result of the ``apps.Start`` call and + +:: + + app->SetStopTime (stopTime); + +as a result of the ``apps.Stop`` call. + +The ultimate result of these calls is that we want to have the simulator +automatically make calls into our ``Applications`` to tell them when to +start and stop. In the case of ``MyApp``, it inherits from class +``Application`` and overrides ``StartApplication``, and +``StopApplication``. These are the functions that will be called by +the simulator at the appropriate time. In the case of ``MyApp`` you +will find that ``MyApp::StartApplication`` does the initial ``Bind``, +and ``Connect`` on the socket, and then starts data flowing by calling +``MyApp::SendPacket``. ``MyApp::StopApplication`` stops generating +packets by cancelling any pending send events and closing the socket. + +One of the nice things about |ns3| is that you can completely +ignore the implementation details of how your ``Application`` is +"automagically" called by the simulator at the correct time. But since +we have already ventured deep into |ns3| already, let's go for it. + +If you look at ``src/node/application.cc`` you will find that the +``SetStartTime`` method of an ``Application`` just sets the member +variable ``m_startTime`` and the ``SetStopTime`` method just sets +``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 ``NodeList``. + +Take a look at ``src/node/node-list.cc`` and search for +``NodeList::Add``. The public static implementation calls into a private +implementation called ``NodeListPriv::Add``. This is a relatively common +idom in |ns3|. So, take a look at ``NodeListPriv::Add``. There +you will find, + +:: + + Simulator::ScheduleWithContext (index, TimeStep (0), &Node::Start, node); + +This tells you that whenever a ``Node`` is created in a simulation, as +a side-effect, a call to that node's ``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 ``Node`` telling it that +the simulation has started, not a call for action telling the ``Node`` +to start doing something. + +So, ``NodeList::Add`` indirectly schedules a call to ``Node::Start`` +at time zero to advise a new node that the simulation has started. If you +look in ``src/node/node.h`` you will, however, not find a method called +``Node::Start``. It turns out that the ``Start`` method is inherited +from class ``Object``. All objects in the system can be notified when +the simulation starts, and objects of class ``Node`` are just one kind +of those objects. + +Take a look at ``src/core/object.cc`` next and search for ``Object::Start``. +This code is not as straightforward as you might have expected since +|ns3| ``Objects`` support aggregation. The code in +``Object::Start`` then loops through all of the objects that have been +aggregated together and calls their ``DoStart`` method. This is another +idiom that is very common in |ns3|. 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 ``MethodName`` for the public API and ``DoMethodName`` for +the private API. + +This tells us that we should look for a ``Node::DoStart`` method in +``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 +``device->Start`` and ``application->Start`` respectively. + +You may already know that classes ``Device`` and ``Application`` both +inherit from class ``Object`` and so the next step will be to look at +what happens when ``Application::DoStart`` is called. Take a look at +``src/node/application.cc`` and you will find: + +:: + + 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 (); + } + +Here, we finally come to the end of the trail. If you have kept it all straight, +when you implement an |ns3| ``Application``, your new application +inherits from class ``Application``. You override the ``StartApplication`` +and ``StopApplication`` methods and provide mechanisms for starting and +stopping the flow of data out of your new ``Application``. When a ``Node`` +is created in the simulation, it is added to a global ``NodeList``. The act +of adding a node to this ``NodeList`` causes a simulator event to be scheduled +for time zero which calls the ``Node::Start`` method of the newly added +``Node`` to be called when the simulation starts. Since a ``Node`` inherits +from ``Object``, this calls the ``Object::Start`` method on the ``Node`` +which, in turn, calls the ``DoStart`` methods on all of the ``Objects`` +aggregated to the ``Node`` (think mobility models). Since the ``Node`` +``Object`` has overridden ``DoStart``, that method is called when the +simulation starts. The ``Node::DoStart`` method calls the ``Start`` methods +of all of the ``Applications`` on the node. Since ``Applications`` are +also ``Objects``, this causes ``Application::DoStart`` to be called. When +``Application::DoStart`` is called, it schedules events for the +``StartApplication`` and ``StopApplication`` calls on the ``Application``. +These calls are designed to start and stop the flow of data from the +``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 |ns3|. + +The MyApp Application +~~~~~~~~~~~~~~~~~~~~~ + +The ``MyApp`` ``Application`` needs a constructor and a destructor, +of course: + +:: + + 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; + } + +The existence of the next bit of code is the whole reason why we wrote this +``Application`` in the first place. + +:: + + void + MyApp::Setup (Ptr 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; + } + +This code should be pretty self-explanatory. We are just initializing member +variables. The important one from the perspective of tracing is the +``Ptr socket`` which we needed to provide to the application +during configuration time. Recall that we are going to create the ``Socket`` +as a ``TcpSocket`` (which is implemented by ``TcpNewReno``) and hook +its "CongestionWindow" trace source before passing it to the ``Setup`` +method. + +:: + + void + MyApp::StartApplication (void) + { + m_running = true; + m_packetsSent = 0; + m_socket->Bind (); + m_socket->Connect (m_peer); + SendPacket (); + } + +The above code is the overridden implementation ``Application::StartApplication`` +that will be automatically called by the simulator to start our ``Application`` +running at the appropriate time. You can see that it does a ``Socket`` ``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 ``Connect`` will do what is required to establish a connection +with the TCP at ``Address`` m_peer. It should now be clear why we need to defer +a lot of this to simulation time, since the ``Connect`` is going to need a fully +functioning network to complete. After the ``Connect``, the ``Application`` +then starts creating simulation events by calling ``SendPacket``. + +The next bit of code explains to the ``Application`` how to stop creating +simulation events. + +:: + + void + MyApp::StopApplication (void) + { + m_running = false; + + if (m_sendEvent.IsRunning ()) + { + Simulator::Cancel (m_sendEvent); + } + + if (m_socket) + { + m_socket->Close (); + } + } + +Every time a simulation event is scheduled, an ``Event`` is created. If the +``Event`` is pending execution or executing, its method ``IsRunning`` will +return ``true``. In this code, if ``IsRunning()`` returns true, we +``Cancel`` the event which removes it from the simulator event queue. By +doing this, we break the chain of events that the ``Application`` is using to +keep sending its ``Packets`` and the ``Application`` goes quiet. After we +quiet the ``Application`` we ``Close`` the socket which tears down the TCP +connection. + +The socket is actually deleted in the destructor when the ``m_socket = 0`` is +executed. This removes the last reference to the underlying Ptr which +causes the destructor of that Object to be called. + +Recall that ``StartApplication`` called ``SendPacket`` to start the +chain of events that describes the ``Application`` behavior. + +:: + + void + MyApp::SendPacket (void) + { + Ptr packet = Create (m_packetSize); + m_socket->Send (packet); + + if (++m_packetsSent < m_nPackets) + { + ScheduleTx (); + } + } + +Here, you see that ``SendPacket`` does just that. It creates a ``Packet`` +and then does a ``Send`` which, if you know Berkeley Sockets, is probably +just what you expected to see. + +It is the responsibility of the ``Application`` to keep scheduling the +chain of events, so the next lines call ``ScheduleTx`` to schedule another +transmit event (a ``SendPacket``) until the ``Application`` decides it +has sent enough. + +:: + + void + MyApp::ScheduleTx (void) + { + if (m_running) + { + Time tNext (Seconds (m_packetSize * 8 / static_cast (m_dataRate.GetBitRate ()))); + m_sendEvent = Simulator::Schedule (tNext, &MyApp::SendPacket, this); + } + } + +Here, you see that ``ScheduleTx`` does exactly that. If the ``Application`` +is running (if ``StopApplication`` has not been called) it will schedule a +new event, which calls ``SendPacket`` again. The alert reader will spot +something that also trips up new users. The data rate of an ``Application`` is +just that. It has nothing to do with the data rate of an underlying ``Channel``. +This is the rate at which the ``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 ``Application`` to the same +data rate as your underlying ``Channel`` you will eventually get a buffer overflow. + +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: + +:: + + static void + CwndChange (uint32_t oldCwnd, uint32_t newCwnd) + { + NS_LOG_UNCOND (Simulator::Now ().GetSeconds () << "\t" << newCwnd); + } + +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. + +:: + + static void + RxDrop (Ptr p) + { + NS_LOG_UNCOND ("RxDrop at " << Simulator::Now ().GetSeconds ()); + } + +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 ``NetDevice``. If you take a small detour to the +source (``src/devices/point-to-point/point-to-point-net-device.cc``) you will +see that this trace source refers to ``PointToPointNetDevice::m_phyRxDropTrace``. +If you then look in ``src/devices/point-to-point/point-to-point-net-device.h`` +for this member variable, you will find that it is declared as a +``TracedCallback >``. This should tell you that the +callback target should be a function that returns void and takes a single +parameter which is a ``Ptr`` -- just what we have above. + +The Main Program +~~~~~~~~~~~~~~~~ + +The following code should be very familiar to you by now: + +:: + + 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); + +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. + +|ns3| provides ``ErrorModel`` objects which can be attached to +``Channels``. We are using the ``RateErrorModel`` which allows us +to introduce errors into a ``Channel`` at a given *rate*. + +:: + + Ptr em = CreateObjectWithAttributes ( + "RanVar", RandomVariableValue (UniformVariable (0., 1.)), + "ErrorRate", DoubleValue (0.00001)); + devices.Get (1)->SetAttribute ("ReceiveErrorModel", PointerValue (em)); + +The above code instantiates a ``RateErrorModel`` Object. Rather than +using the two-step process of instantiating it and then setting Attributes, +we use the convenience function ``CreateObjectWithAttributes`` which +allows us to do both at the same time. We set the "RanVar" +``Attribute`` to a random variable that generates a uniform distribution +from 0 to 1. We also set the "ErrorRate" ``Attribute``. +We then set the resulting instantiated ``RateErrorModel`` as the error +model used by the point-to-point ``NetDevice``. This will give us some +retransmissions and make our plot a little more interesting. + +:: + + InternetStackHelper stack; + stack.Install (nodes); + + Ipv4AddressHelper address; + address.SetBase ("10.1.1.0", "255.255.255.252"); + Ipv4InterfaceContainer interfaces = address.Assign (devices); + +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 ``PacketSink`` ``Application`` is commonly +used in |ns3| for that purpose. + +:: + + 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.)); + +This should all be familiar, with the exception of, + +:: + + PacketSinkHelper packetSinkHelper ("ns3::TcpSocketFactory", + InetSocketAddress (Ipv4Address::GetAny (), sinkPort)); + +This code instantiates a ``PacketSinkHelper`` and tells it to create sockets +using the class ``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 ``PacketSinkHelper`` +a string that specifies a ``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 ``Application`` which address and port it +should ``Bind`` to. + +The next two lines of code will create the socket and connect the trace source. + +:: + + Ptr ns3TcpSocket = Socket::CreateSocket (nodes.Get (0), + TcpSocketFactory::GetTypeId ()); + ns3TcpSocket->TraceConnectWithoutContext ("CongestionWindow", + MakeCallback (&CwndChange)); + +The first statement calls the static member function ``Socket::CreateSocket`` +and provides a ``Node`` and an explicit ``TypeId`` for the object factory +used to create the socket. This is a slightly lower level call than the +``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 ``TcpSocket`` is created and attached to the ``Node``, we can +use ``TraceConnectWithoutContext`` to connect the CongestionWindow trace +source to our trace sink. + +Recall that we coded an ``Application`` so we could take that ``Socket`` +we just made (during configuration time) and use it in simulation time. We now +have to instantiate that ``Application``. We didn't go to any trouble to +create a helper to manage the ``Application`` so we are going to have to +create and install it "manually". This is actually quite easy: + +:: + + Ptr app = CreateObject (); + app->Setup (ns3TcpSocket, sinkAddress, 1040, 1000, DataRate ("1Mbps")); + nodes.Get (0)->AddApplication (app); + app->Start (Seconds (1.)); + app->Stop (Seconds (20.)); + +The first line creates an ``Object`` of type ``MyApp`` -- our +``Application``. The second line tells the ``Application`` what +``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 ``MyApp Application`` to the source node +and explicitly call the ``Start`` and ``Stop`` methods on the +``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 ``NetDevice`` +to our callback now. + +:: + + devices.Get (1)->TraceConnectWithoutContext("PhyRxDrop", MakeCallback (&RxDrop)); + +It should now be obvious that we are getting a reference to the receiving +``Node NetDevice`` from its container and connecting the trace source defined +by the attribute "PhyRxDrop" on that device to the trace sink ``RxDrop``. + +Finally, we tell the simulator to override any ``Applications`` and just +stop processing events at 20 seconds into the simulation. + +:: + + Simulator::Stop (Seconds(20)); + Simulator::Run (); + Simulator::Destroy (); + + return 0; + } + +Recall that as soon as ``Simulator::Run`` is called, configuration time +ends, and simulation time begins. All of the work we orchestrated by +creating the ``Application`` and teaching it how to connect and send +data actually happens during this function call. + +As soon as ``Simulator::Run`` returns, the simulation is complete and +we enter the teardown phase. In this case, ``Simulator::Destroy`` takes +care of the gory details and we just return a success code after it completes. + +Running fifth.cc +++++++++++++++++ + +Since we have provided the file ``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. + +:: + + ./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 + ... + +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 ``cwnd.dat``: + +:: + + ./waf --run fifth > cwnd.dat 2>&1 + +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 +``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: + +:: + + 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 + +You should now have a graph of the congestion window versus time sitting in the +file "cwnd.png" that looks like: + +.. figure:: figures/cwnd.png + +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 ``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 |ns3| 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 |ns3| to do just that and complete +the picture. + +We provide a script that writes the cwnd change and drop events developed in +the example ``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. + +A sixth.cc Walkthrough +~~~~~~~~~~~~~~~~~~~~~~ + +Let's take a look at the changes required to go from ``fifth.cc`` to +``sixth.cc``. Open ``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. + +:: + + static void + CwndChange (Ptr 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 file, Ptr p) + { + NS_LOG_UNCOND ("RxDrop at " << Simulator::Now ().GetSeconds ()); + file->Write(Simulator::Now(), p); + } + +We have added a "stream" parameter to the ``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 |ns3| callback system, which as you may recall, requires objects +that obey value semantics. Further notice that we have added the following +line in the ``CwndChange`` trace sink implementation: + +:: + + *stream->GetStream () << Simulator::Now ().GetSeconds () << "\t" << oldCwnd << "\t" << newCwnd << std::endl; + +This would be very familiar code if you replaced ``*stream->GetStream ()`` +with ``std::cout``, as in: + +:: + + std::cout << Simulator::Now ().GetSeconds () << "\t" << oldCwnd << "\t" << newCwnd << std::endl; + +This illustrates that the ``Ptr`` is really just +carrying around a ``std::ofstream`` for you, and you can use it here like +any other output stream. + +A similar situation happens in ``RxDrop`` except that the object being +passed around (a ``Ptr``) 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: + +:: + + file->Write(Simulator::Now(), p); + +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 ``main`` function, you will find new code to do just that: + +:: + + AsciiTraceHelper asciiTraceHelper; + Ptr stream = asciiTraceHelper.CreateFileStream ("sixth.cwnd"); + ns3TcpSocket->TraceConnectWithoutContext ("CongestionWindow", MakeBoundCallback (&CwndChange, stream)); + + ... + + PcapHelper pcapHelper; + Ptr file = pcapHelper.CreateFile ("sixth.pcap", std::ios::out, PcapHelper::DLT_PPP); + devices.Get (1)->TraceConnectWithoutContext("PhyRxDrop", MakeBoundCallback (&RxDrop, file)); + +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 ``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 |ns3| object for lifetime management +and copy constructor issue resolution. + +We then take this |ns3| object representing the file and pass it to +``MakeBoundCallback()``. This function creates a callback just like +``MakeCallback()``, but it "binds" a new value to the callback. This +value is added to the callback before it is called. + +Essentially, ``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 ``CwndChange`` sink to match the one shown above, which +includes the "extra" parameter ``Ptr stream``. + +In the second section of code in the snippet above, we instantiate a +``PcapHelper`` to do the same thing for our pcap trace file that we did +with the ``AsciiTraceHelper``. The line of code, + +:: + + Ptr file = pcapHelper.CreateFile ("sixth.pcap", "w", PcapHelper::DLT_PPP); + +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 ``bpf.h`` if you are +familar with pcap. In this case, ``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 ``src/helper/trace-helper.h"`` if you are interested in seeing +the list. The entries in the list match those in ``bpf.h`` but we duplicate +them to avoid a pcap source dependence. + +A |ns3| object representing the pcap file is returned from ``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, + +:: + + Ptr file ... + Ptr stream ... + +The underlying objects are entirely different. For example, the +Ptr is a smart pointer to an |ns3| Object that is a +fairly heaviweight thing that supports ``Attributes`` and is integrated into +the config system. The Ptr, 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 ``src/common/pcap-file-object.h`` in the +distribution and notice, + +:: + + class PcapFileWrapper : public Object + +that class ``PcapFileWrapper`` is an |ns3| Object by virtue of +its inheritance. Then look at ``src/common/output-stream-wrapper.h`` and +notice, + +:: + + class OutputStreamWrapper : public SimpleRefCount + +that this object is not an |ns3| 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 it does not necessarily +mean that "something" is an |ns3| Object on which you can hang |ns3| +``Attributes``, for example. + +Now, back to the example. If you now build and run this example, + +:: + + ./waf --run sixth + +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 |ns3| distribution. + +:: + + sixth.cwnd sixth.pcap + +Since "sixth.cwnd" is an ASCII text file, you can view it with ``cat`` +or your favorite file viewer. + +:: + + 1.20919 536 1072 + 1.21511 1072 1608 + ... + 9.30922 8893 8925 + 9.31754 8925 8957 + +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 ``tcpdump``. + +:: + + 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 + +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 +|ns3| 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: + +:: + + static void + CwndChange (Ptr 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 stream = asciiTraceHelper.CreateFileStream ("sixth.cwnd"); + ns3TcpSocket->TraceConnectWithoutContext ("CongestionWindow", MakeBoundCallback (&CwndChange, stream)); + + ... + + static void + RxDrop (Ptr file, Ptr p) + { + NS_LOG_UNCOND ("RxDrop at " << Simulator::Now ().GetSeconds ()); + file->Write(Simulator::Now(), p); + } + + ... + + PcapHelper pcapHelper; + Ptr file = pcapHelper.CreateFile ("sixth.pcap", "w", PcapHelper::DLT_PPP); + devices.Get (1)->TraceConnectWithoutContext("PhyRxDrop", MakeBoundCallback (&RxDrop, file)); + +Using Trace Helpers +******************* + +The |ns3| 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: + +:: + + pointToPoint.EnablePcapAll ("second"); + pointToPoint.EnablePcap ("second", p2pNodes.Get (0)->GetId (), 0); + csma.EnablePcap ("third", csmaDevices.Get (0), true); + pointToPoint.EnableAsciiAll (ascii.CreateFileStream ("myfirst.tr")); + +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 |ns3|: +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 |ns3| device +conceptual model, and also the conceptual models of the various device helpers. +Following naturally from this, the files created follow a +-- 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 |ns3| +protocol stack conceptual model, and also the conceptual models of internet +stack helpers. Naturally, the trace files should follow a +-- 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. + +:: + + | pcap | ascii | + -----------------+------+-------| + Device Helper | | | + -----------------+------+-------| + Protocol Helper | | | + -----------------+------+-------| + +We use an approach called a ``mixin`` to add tracing functionality to our +helper classes. A ``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 +``mixins``. + +Pcap Tracing Device Helpers ++++++++++++++++++++++++++++ + +The goal of these helpers is to make it easy to add a consistent pcap trace +facility to an |ns3| 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 +``src/helper/trace-helper.h`` if you want to follow the discussion while +looking at real code. + +The class ``PcapHelperForDevice`` is a ``mixin`` provides the high level +functionality for using pcap tracing in an |ns3| device. Every device +must implement a single virtual method inherited from this class. + +:: + + virtual void EnablePcapInternal (std::string prefix, Ptr nd, bool promiscuous, bool explicitFilename) = 0; + +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``PcapUserHelperForDevice`` reduce to calling this single device-dependent +implementation method. For example, the lowest level pcap method, + +:: + + void EnablePcap (std::string prefix, Ptr nd, bool promiscuous = false, bool explicitFilename = false); + +will call the device implementation of ``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 ``EnablePcapInternal`` correctly. + +Pcap Tracing Device Helper Methods +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +:: + + void EnablePcap (std::string prefix, Ptr 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); + +In each of the methods shown above, there is a default parameter called +``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, + +:: + + Ptr nd; + ... + helper.EnablePcap ("prefix", nd, true); + +will enable promiscuous mode captures on the ``NetDevice`` specified by ``nd``. + +The first two methods also include a default parameter called ``explicitFilename`` +that will be discussed below. + +You are encouraged to peruse the Doxygen for class ``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 +``Ptr`` to an ``EnablePcap`` method. The ``Ptr`` is +implicit since the net device must belong to exactly one ``Node``. +For example, + +:: + + Ptr nd; + ... + helper.EnablePcap ("prefix", nd); + +You can enable pcap tracing on a particular node/net-device pair by providing a +``std::string`` representing an object name service string to an +``EnablePcap`` method. The ``Ptr`` is looked up from the name +string. Again, the ```` is implicit since the named net device must +belong to exactly one ``Node``. For example, + +:: + + Names::Add ("server" ...); + Names::Add ("server/eth0" ...); + ... + helper.EnablePcap ("prefix", "server/ath0"); + +You can enable pcap tracing on a collection of node/net-device pairs by +providing a ``NetDeviceContainer``. For each ``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 ```` is +implicit since the found net device must belong to exactly one ``Node``. +For example, + +:: + + NetDeviceContainer d = ...; + ... + helper.EnablePcap ("prefix", d); + +You can enable pcap tracing on a collection of node/net-device pairs by +providing a ``NodeContainer``. For each ``Node`` in the ``NodeContainer`` +its attached ``NetDevices`` are iterated. For each ``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. + +:: + + NodeContainer n; + ... + helper.EnablePcap ("prefix", n); + +You can enable pcap tracing on the basis of node ID and device ID as well as +with explicit ``Ptr``. Each ``Node`` in the system has an integer node ID +and each device connected to a node has an integer device ID. + +:: + + helper.EnablePcap ("prefix", 21, 1); + +Finally, you can enable pcap tracing for all devices in the system, with the +same type as that managed by the device helper. + +:: + + helper.EnablePcapAll ("prefix"); + +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 +|ns3| system are of the form "--.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 |ns3| 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, + +:: + + void EnablePcap (std::string prefix, Ptr nd, bool promiscuous = false, bool explicitFilename = false); + void EnablePcap (std::string prefix, std::string ndName, bool promiscuous = false, bool explicitFilename = false); + +have a default parameter called ``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: + +:: + + Ptr nd; + ... + helper.EnablePcap ("my-pcap-file.pcap", nd, true, true); + +The first ``true`` parameter enables promiscuous mode traces and the second +tells the helper to interpret the ``prefix`` parameter as a complete filename. + +Ascii Tracing Device Helpers +++++++++++++++++++++++++++++ + +The behavior of the ascii trace helper ``mixin`` is substantially similar to +the pcap version. Take a look at ``src/helper/trace-helper.h`` if you want to +follow the discussion while looking at real code. + +The class ``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 ``mixin``. + +:: + + virtual void EnableAsciiInternal (Ptr stream, + std::string prefix, + Ptr nd, + bool explicitFilename) = 0; + + +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 ``AsciiTraceHelperForDevice`` reduce to calling this single device- +dependent implementation method. For example, the lowest level ascii trace +methods, + +:: + + void EnableAscii (std::string prefix, Ptr nd, bool explicitFilename = false); + void EnableAscii (Ptr stream, Ptr nd); + + +will call the device implementation of ``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 +``EnablAsciiInternal`` correctly. + +Ascii Tracing Device Helper Methods +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +:: + + void EnableAscii (std::string prefix, Ptr nd, bool explicitFilename = false); + void EnableAscii (Ptr stream, Ptr nd); + + void EnableAscii (std::string prefix, std::string ndName, bool explicitFilename = false); + void EnableAscii (Ptr stream, std::string ndName); + + void EnableAscii (std::string prefix, NetDeviceContainer d); + void EnableAscii (Ptr stream, NetDeviceContainer d); + + void EnableAscii (std::string prefix, NodeContainer n); + void EnableAscii (Ptr stream, NodeContainer n); + + void EnableAsciiAll (std::string prefix); + void EnableAsciiAll (Ptr stream); + + void EnableAscii (std::string prefix, uint32_t nodeid, uint32_t deviceid, bool explicitFilename); + void EnableAscii (Ptr stream, uint32_t nodeid, uint32_t deviceid); + +You are encouraged to peruse the Doxygen for class ``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 -- 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 ``Ptr`` to an ``EnableAscii`` +method. The ``Ptr`` is implicit since the net device must belong to +exactly one ``Node``. For example, + +:: + + Ptr nd; + ... + helper.EnableAscii ("prefix", nd); + +The first four methods also include a default parameter called ``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: + +:: + + Ptr nd1; + Ptr nd2; + ... + Ptr stream = asciiTraceHelper.CreateFileStream ("trace-file-name.tr"); + ... + helper.EnableAscii (stream, nd1); + helper.EnableAscii (stream, nd2); + + +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 +``std::string`` representing an object name service string to an +``EnablePcap`` method. The ``Ptr`` is looked up from the name +string. Again, the ```` is implicit since the named net device must +belong to exactly one ``Node``. For example, + +:: + + Names::Add ("client" ...); + Names::Add ("client/eth0" ...); + Names::Add ("server" ...); + Names::Add ("server/eth0" ...); + ... + helper.EnableAscii ("prefix", "client/eth0"); + helper.EnableAscii ("prefix", "server/eth0"); + +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: + +:: + + Names::Add ("client" ...); + Names::Add ("client/eth0" ...); + Names::Add ("server" ...); + Names::Add ("server/eth0" ...); + ... + Ptr stream = asciiTraceHelper.CreateFileStream ("trace-file-name.tr"); + ... + helper.EnableAscii (stream, "client/eth0"); + helper.EnableAscii (stream, "server/eth0"); + +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 ``NetDeviceContainer``. For each ``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 ```` is +implicit since the found net device must belong to exactly one ``Node``. +For example, + +:: + + NetDeviceContainer d = ...; + ... + helper.EnableAscii ("prefix", d); + +This would result in a number of ascii trace files being created, each of which +follows the --.tr convention. Combining all of the +traces into a single file is accomplished similarly to the examples above: + +:: + + NetDeviceContainer d = ...; + ... + Ptr stream = asciiTraceHelper.CreateFileStream ("trace-file-name.tr"); + ... + helper.EnableAscii (stream, d); + +You can enable ascii tracing on a collection of node/net-device pairs by +providing a ``NodeContainer``. For each ``Node`` in the ``NodeContainer`` +its attached ``NetDevices`` are iterated. For each ``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. + +:: + + NodeContainer n; + ... + helper.EnableAscii ("prefix", n); + +This would result in a number of ascii trace files being created, each of which +follows the --.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 ``Ptr``. Each ``Node`` in the system has an integer node ID +and each device connected to a node has an integer device ID. + +:: + + helper.EnableAscii ("prefix", 21, 1); + +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. + +:: + + helper.EnableAsciiAll ("prefix"); + +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 --.tr convention. Combining +all of the traces into a single file is accomplished similarly to the examples +above. + +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 |ns3| system are of the form "--.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 |ns3| 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 ``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. + +Pcap Tracing Protocol Helpers ++++++++++++++++++++++++++++++ + +The goal of these ``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 ``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 +``Ipv4``. To specify traces in similar protocols, just substitute the +appropriate type. For example, use a ``Ptr`` instead of a +``Ptr`` and call ``EnablePcapIpv6`` instead of ``EnablePcapIpv4``. + +The class ``PcapHelperForIpv4`` provides the high level functionality for +using pcap tracing in the ``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 ``Ipv6``, for example, but the only +difference will be in the method names and signatures. Different method names +are required to disambiguate class ``Ipv4`` from ``Ipv6`` which are both +derived from class ``Object``, and methods that share the same signature. + +:: + + virtual void EnablePcapIpv4Internal (std::string prefix, + Ptr ipv4, + uint32_t interface, + bool explicitFilename) = 0; + +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 +``PcapHelperForIpv4`` reduce to calling this single device-dependent +implementation method. For example, the lowest level pcap method, + +:: + + void EnablePcapIpv4 (std::string prefix, Ptr ipv4, uint32_t interface, bool explicitFilename = false); + + +will call the device implementation of ``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 ``EnablePcapIpv4Internal`` correctly. + +Pcap Tracing Protocol Helper Methods +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +These methods are designed to be in one-to-one correspondence with the ``Node``- +and ``NetDevice``- centric versions of the device versions. Instead of +``Node`` and ``NetDevice`` pair constraints, we use protocol and interface +constraints. + +Note that just like in the device version, there are six methods: + +:: + + void EnablePcapIpv4 (std::string prefix, Ptr 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); + +You are encouraged to peruse the Doxygen for class ``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 +``Ptr`` and ``interface`` to an ``EnablePcap`` method. For example, + +:: + + Ptr ipv4 = node->GetObject (); + ... + helper.EnablePcapIpv4 ("prefix", ipv4, 0); + +You can enable pcap tracing on a particular node/net-device pair by providing a +``std::string`` representing an object name service string to an +``EnablePcap`` method. The ``Ptr`` is looked up from the name +string. For example, + +:: + + Names::Add ("serverIPv4" ...); + ... + helper.EnablePcapIpv4 ("prefix", "serverIpv4", 1); + +You can enable pcap tracing on a collection of protocol/interface pairs by +providing an ``Ipv4InterfaceContainer``. For each ``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, + +:: + + 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); + +You can enable pcap tracing on a collection of protocol/interface pairs by +providing a ``NodeContainer``. For each ``Node`` in the ``NodeContainer`` +the appropriate protocol is found. For each protocol, its interfaces are +enumerated and tracing is enabled on the resulting pairs. For example, + +:: + + NodeContainer n; + ... + helper.EnablePcapIpv4 ("prefix", n); + +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 ``Ptr`` and the appropriate +protocol is looked up in the node. The resulting protocol and interface are +used to specify the resulting trace source. + +:: + + helper.EnablePcapIpv4 ("prefix", 21, 1); + +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. + +:: + + helper.EnablePcapIpv4All ("prefix"); + +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 |ns3| system are of the form +"--.pcap". In the case of protocol traces, +there is a one-to-one correspondence between protocols and ``Nodes``. +This is because protocol ``Objects`` are aggregated to ``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 +"-n-i.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 |ns3| 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 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 ``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. + +Ascii Tracing Protocol Helpers +++++++++++++++++++++++++++++++ + +The behavior of the ascii trace helpers is substantially similar to the pcap +case. Take a look at ``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 +``Ipv4``. To specify traces in similar protocols, just substitute the +appropriate type. For example, use a ``Ptr`` instead of a +``Ptr`` and call ``EnableAsciiIpv6`` instead of ``EnableAsciiIpv4``. + +The class ``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. + +:: + + virtual void EnableAsciiIpv4Internal (Ptr stream, + std::string prefix, + Ptr ipv4, + uint32_t interface, + bool explicitFilename) = 0; + +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 +``PcapAndAsciiTraceHelperForIpv4`` reduce to calling this single device- +dependent implementation method. For example, the lowest level ascii trace +methods, + +:: + + void EnableAsciiIpv4 (std::string prefix, Ptr ipv4, uint32_t interface, bool explicitFilename = false); + void EnableAsciiIpv4 (Ptr stream, Ptr ipv4, uint32_t interface); + + +will call the device implementation of ``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 +``EnablAsciiIpv4Internal`` correctly. + +Ascii Tracing Protocol Helper Methods +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +:: + + void EnableAsciiIpv4 (std::string prefix, Ptr ipv4, uint32_t interface, bool explicitFilename = false); + void EnableAsciiIpv4 (Ptr stream, Ptr ipv4, uint32_t interface); + + void EnableAsciiIpv4 (std::string prefix, std::string ipv4Name, uint32_t interface, bool explicitFilename = false); + void EnableAsciiIpv4 (Ptr stream, std::string ipv4Name, uint32_t interface); + + void EnableAsciiIpv4 (std::string prefix, Ipv4InterfaceContainer c); + void EnableAsciiIpv4 (Ptr stream, Ipv4InterfaceContainer c); + + void EnableAsciiIpv4 (std::string prefix, NodeContainer n); + void EnableAsciiIpv4 (Ptr stream, NodeContainer n); + + void EnableAsciiIpv4All (std::string prefix); + void EnableAsciiIpv4All (Ptr stream); + + void EnableAsciiIpv4 (std::string prefix, uint32_t nodeid, uint32_t deviceid, bool explicitFilename); + void EnableAsciiIpv4 (Ptr stream, uint32_t nodeid, uint32_t interface); + +You are encouraged to peruse the Doxygen for class ``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 -n- +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 ``Ptr`` and an ``interface`` +to an ``EnableAscii`` method. +For example, + +:: + + Ptr ipv4; + ... + helper.EnableAsciiIpv4 ("prefix", ipv4, 1); + +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: + +:: + + Ptr protocol1 = node1->GetObject (); + Ptr protocol2 = node2->GetObject (); + ... + Ptr stream = asciiTraceHelper.CreateFileStream ("trace-file-name.tr"); + ... + helper.EnableAsciiIpv4 (stream, protocol1, 1); + helper.EnableAsciiIpv4 (stream, protocol2, 1); + +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 +``std::string`` representing an object name service string to an +``EnablePcap`` method. The ``Ptr`` is looked up from the name +string. The ```` in the resulting filenames is implicit since there +is a one-to-one correspondence between protocol instances and nodes, +For example, + +:: + + Names::Add ("node1Ipv4" ...); + Names::Add ("node2Ipv4" ...); + ... + helper.EnableAsciiIpv4 ("prefix", "node1Ipv4", 1); + helper.EnableAsciiIpv4 ("prefix", "node2Ipv4", 1); + +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: + +:: + + Names::Add ("node1Ipv4" ...); + Names::Add ("node2Ipv4" ...); + ... + Ptr stream = asciiTraceHelper.CreateFileStream ("trace-file-name.tr"); + ... + helper.EnableAsciiIpv4 (stream, "node1Ipv4", 1); + helper.EnableAsciiIpv4 (stream, "node2Ipv4", 1); + +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 ``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 ```` is implicit since +there is a one-to-one correspondence between each protocol and its node. +For example, + +:: + + 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); + +This would result in a number of ascii trace files being created, each of which +follows the -n-i.tr convention. Combining all of the +traces into a single file is accomplished similarly to the examples above: + +:: + + 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 stream = asciiTraceHelper.CreateFileStream ("trace-file-name.tr"); + ... + helper.EnableAsciiIpv4 (stream, interfaces); + +You can enable ascii tracing on a collection of protocol/interface pairs by +providing a ``NodeContainer``. For each ``Node`` in the ``NodeContainer`` +the appropriate protocol is found. For each protocol, its interfaces are +enumerated and tracing is enabled on the resulting pairs. For example, + +:: + + NodeContainer n; + ... + helper.EnableAsciiIpv4 ("prefix", n); + +This would result in a number of ascii trace files being created, each of which +follows the --.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 ``Ptr`` and the appropriate +protocol is looked up in the node. The resulting protocol and interface are +used to specify the resulting trace source. + +:: + + helper.EnableAsciiIpv4 ("prefix", 21, 1); + +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. + +:: + + helper.EnableAsciiIpv4All ("prefix"); + +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 -n-i--.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 |ns3| 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 ``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. + +Summary +******* + +|ns3| 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 +|ns3| and so recommend becoming as familiar as possible with it. It is +probably the case that understanding the rest of the |ns3| system will +be quite simple once you have mastered the tracing system diff -r c9133c87760d -r 7ff69b244b5b doc/tutorial/source/tweaking.rst --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/tutorial/source/tweaking.rst Sun Jan 02 22:57:32 2011 -0800 @@ -0,0 +1,996 @@ +.. include:: replace.txt + + +Tweaking +-------- + +Using the Logging Module +************************ + +We have already taken a brief look at the |ns3| logging module while +going over the ``first.cc`` script. We will now take a closer look and +see what kind of use-cases the logging subsystem was designed to cover. + +Logging Overview +++++++++++++++++ +Many large systems support some kind of message logging facility, and +|ns3| is not an exception. In some cases, only error messages are +logged to the "operator console" (which is typically ``stderr`` in Unix- +based systems). In other systems, warning messages may be output as well as +more detailed informational messages. In some cases, logging facilities are +used to output debug messages which can quickly turn the output into a blur. + +|ns3| takes the view that all of these verbosity levels are useful +and we provide a selectable, multi-level approach to message logging. Logging +can be disabled completely, enabled on a component-by-component basis, or +enabled globally; and it provides selectable verbosity levels. The +|ns3| log module provides a straightforward, relatively easy to use +way to get useful information out of your simulation. + +You should understand that we do provide a general purpose mechanism --- +tracing --- to get data out of your models which should be preferred for +simulation output (see the tutorial section Using the Tracing System for +more details on our tracing system). Logging should be preferred for +debugging information, warnings, error messages, or any time you want to +easily get a quick message out of your scripts or models. + +There are currently seven levels of log messages of increasing verbosity +defined in the system. + +* NS_LOG_ERROR --- Log error messages; +* NS_LOG_WARN --- Log warning messages; +* NS_LOG_DEBUG --- Log relatively rare, ad-hoc debugging messages; +* NS_LOG_INFO --- Log informational messages about program progress; +* NS_LOG_FUNCTION --- Log a message describing each function called; +* NS_LOG_LOGIC -- Log messages describing logical flow within a function; +* NS_LOG_ALL --- Log everything. + +We also provide an unconditional logging level that is always displayed, +irrespective of logging levels or component selection. + +* NS_LOG_UNCOND -- Log the associated message unconditionally. + +Each level can be requested singly or cumulatively; and logging can be set +up using a shell environment variable (NS_LOG) or by logging system function +call. As was seen earlier in the tutorial, the logging system has Doxygen +documentation and now would be a good time to peruse the Logging Module +documentation if you have not done so. + +Now that you have read the documentation in great detail, let's use some of +that knowledge to get some interesting information out of the +``scratch/myfirst.cc`` example script you have already built. + +Enabling Logging +++++++++++++++++ +Let's use the NS_LOG environment variable to turn on some more logging, but +first, just to get our bearings, go ahead and run the last script just as you +did previously, + +:: + + ./waf --run scratch/myfirst + +You should see the now familiar output of the first |ns3| example +program + +:: + + Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' + Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' + 'build' finished successfully (0.413s) + Sent 1024 bytes to 10.1.1.2 + Received 1024 bytes from 10.1.1.1 + Received 1024 bytes from 10.1.1.2 + +It turns out that the "Sent" and "Received" messages you see above are +actually logging messages from the ``UdpEchoClientApplication`` and +``UdpEchoServerApplication``. We can ask the client application, for +example, to print more information by setting its logging level via the +NS_LOG environment variable. + +I am going to assume from here on that you are using an sh-like shell that uses +the"VARIABLE=value" syntax. If you are using a csh-like shell, then you +will have to convert my examples to the "setenv VARIABLE value" syntax +required by those shells. + +Right now, the UDP echo client application is responding to the following line +of code in ``scratch/myfirst.cc``, + +:: + + LogComponentEnable("UdpEchoClientApplication", LOG_LEVEL_INFO); + +This line of code enables the ``LOG_LEVEL_INFO`` level of logging. When +we pass a logging level flag, we are actually enabling the given level and +all lower levels. In this case, we have enabled ``NS_LOG_INFO``, +``NS_LOG_DEBUG``, ``NS_LOG_WARN`` and ``NS_LOG_ERROR``. We can +increase the logging level and get more information without changing the +script and recompiling by setting the NS_LOG environment variable like this: + +:: + + export NS_LOG=UdpEchoClientApplication=level_all + +This sets the shell environment variable ``NS_LOG`` to the string, + +:: + + UdpEchoClientApplication=level_all + +The left hand side of the assignment is the name of the logging component we +want to set, and the right hand side is the flag we want to use. In this case, +we are going to turn on all of the debugging levels for the application. If +you run the script with NS_LOG set this way, the |ns3| logging +system will pick up the change and you should see the following output: + +:: + + Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build + Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' + 'build' finished successfully (0.404s) + UdpEchoClientApplication:UdpEchoClient() + UdpEchoClientApplication:SetDataSize(1024) + UdpEchoClientApplication:StartApplication() + UdpEchoClientApplication:ScheduleTransmit() + UdpEchoClientApplication:Send() + Sent 1024 bytes to 10.1.1.2 + Received 1024 bytes from 10.1.1.1 + UdpEchoClientApplication:HandleRead(0x6241e0, 0x624a20) + Received 1024 bytes from 10.1.1.2 + UdpEchoClientApplication:StopApplication() + UdpEchoClientApplication:DoDispose() + UdpEchoClientApplication:~UdpEchoClient() + +The additional debug information provided by the application is from +the NS_LOG_FUNCTION level. This shows every time a function in the application +is called during script execution. Note that there are no requirements in the +|ns3| system that models must support any particular logging +functionality. The decision regarding how much information is logged +is left to the individual model developer. In the case of the echo +applications, a good deal of log output is available. + +You can now see a log of the function calls that were made to the application. +If you look closely you will notice a single colon between the string +``UdpEchoClientApplication`` and the method name where you might have +expected a C++ scope operator (``::``). This is intentional. + +The name is not actually a class name, it is a logging component name. When +there is a one-to-one correspondence between a source file and a class, this +will generally be the class name but you should understand that it is not +actually a class name, and there is a single colon there instead of a double +colon to remind you in a relatively subtle way to conceptually separate the +logging component name from the class name. + +It turns out that in some cases, it can be hard to determine which method +actually generates a log message. If you look in the text above, you may +wonder where the string "``Received 1024 bytes from 10.1.1.2``" comes +from. You can resolve this by OR'ing the ``prefix_func`` level into the +``NS_LOG`` environment variable. Try doing the following, + +:: + + export 'NS_LOG=UdpEchoClientApplication=level_all|prefix_func' + +Note that the quotes are required since the vertical bar we use to indicate an +OR operation is also a Unix pipe connector. + +Now, if you run the script you will see that the logging system makes sure +that every message from the given log component is prefixed with the component +name. + +:: + + Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' + Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' + 'build' finished successfully (0.417s) + UdpEchoClientApplication:UdpEchoClient() + UdpEchoClientApplication:SetDataSize(1024) + UdpEchoClientApplication:StartApplication() + UdpEchoClientApplication:ScheduleTransmit() + UdpEchoClientApplication:Send() + UdpEchoClientApplication:Send(): Sent 1024 bytes to 10.1.1.2 + Received 1024 bytes from 10.1.1.1 + UdpEchoClientApplication:HandleRead(0x6241e0, 0x624a20) + UdpEchoClientApplication:HandleRead(): Received 1024 bytes from 10.1.1.2 + UdpEchoClientApplication:StopApplication() + UdpEchoClientApplication:DoDispose() + UdpEchoClientApplication:~UdpEchoClient() + +You can now see all of the messages coming from the UDP echo client application +are identified as such. The message "Received 1024 bytes from 10.1.1.2" is +now clearly identified as coming from the echo client application. The +remaining message must be coming from the UDP echo server application. We +can enable that component by entering a colon separated list of components in +the NS_LOG environment variable. + +:: + + export 'NS_LOG=UdpEchoClientApplication=level_all|prefix_func: + UdpEchoServerApplication=level_all|prefix_func' + +Warning: You will need to remove the newline after the ``:`` in the +example text above which is only there for document formatting purposes. + +Now, if you run the script you will see all of the log messages from both the +echo client and server applications. You may see that this can be very useful +in debugging problems. + +:: + + Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' + Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' + 'build' finished successfully (0.406s) + UdpEchoServerApplication:UdpEchoServer() + UdpEchoClientApplication:UdpEchoClient() + UdpEchoClientApplication:SetDataSize(1024) + UdpEchoServerApplication:StartApplication() + UdpEchoClientApplication:StartApplication() + UdpEchoClientApplication:ScheduleTransmit() + UdpEchoClientApplication:Send() + UdpEchoClientApplication:Send(): Sent 1024 bytes to 10.1.1.2 + UdpEchoServerApplication:HandleRead(): Received 1024 bytes from 10.1.1.1 + UdpEchoServerApplication:HandleRead(): Echoing packet + UdpEchoClientApplication:HandleRead(0x624920, 0x625160) + UdpEchoClientApplication:HandleRead(): Received 1024 bytes from 10.1.1.2 + UdpEchoServerApplication:StopApplication() + UdpEchoClientApplication:StopApplication() + UdpEchoClientApplication:DoDispose() + UdpEchoServerApplication:DoDispose() + UdpEchoClientApplication:~UdpEchoClient() + UdpEchoServerApplication:~UdpEchoServer() + +It is also sometimes useful to be able to see the simulation time at which a +log message is generated. You can do this by ORing in the prefix_time bit. + +:: + + export 'NS_LOG=UdpEchoClientApplication=level_all|prefix_func|prefix_time: + UdpEchoServerApplication=level_all|prefix_func|prefix_time' + +Again, you will have to remove the newline above. If you run the script now, +you should see the following output: + +:: + + Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' + Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' + 'build' finished successfully (0.418s) + 0s UdpEchoServerApplication:UdpEchoServer() + 0s UdpEchoClientApplication:UdpEchoClient() + 0s UdpEchoClientApplication:SetDataSize(1024) + 1s UdpEchoServerApplication:StartApplication() + 2s UdpEchoClientApplication:StartApplication() + 2s UdpEchoClientApplication:ScheduleTransmit() + 2s UdpEchoClientApplication:Send() + 2s UdpEchoClientApplication:Send(): Sent 1024 bytes to 10.1.1.2 + 2.00369s UdpEchoServerApplication:HandleRead(): Received 1024 bytes from 10.1.1.1 + 2.00369s UdpEchoServerApplication:HandleRead(): Echoing packet + 2.00737s UdpEchoClientApplication:HandleRead(0x624290, 0x624ad0) + 2.00737s UdpEchoClientApplication:HandleRead(): Received 1024 bytes from 10.1.1.2 + 10s UdpEchoServerApplication:StopApplication() + 10s UdpEchoClientApplication:StopApplication() + UdpEchoClientApplication:DoDispose() + UdpEchoServerApplication:DoDispose() + UdpEchoClientApplication:~UdpEchoClient() + UdpEchoServerApplication:~UdpEchoServer() + +You can see that the constructor for the UdpEchoServer was called at a +simulation time of 0 seconds. This is actually happening before the +simulation starts, but the time is displayed as zero seconds. The same is true +for the UdpEchoClient constructor message. + +Recall that the ``scratch/first.cc`` script started the echo server +application at one second into the simulation. You can now see that the +``StartApplication`` method of the server is, in fact, called at one second. +You can also see that the echo client application is started at a simulation +time of two seconds as we requested in the script. + +You can now follow the progress of the simulation from the +``ScheduleTransmit`` call in the client that calls ``Send`` to the +``HandleRead`` callback in the echo server application. Note that the +elapsed time for the packet to be sent across the point-to-point link is 3.69 +milliseconds. You see the echo server logging a message telling you that it +has echoed the packet and then, after another channel delay, you see the echo +client receive the echoed packet in its ``HandleRead`` method. + +There is a lot that is happening under the covers in this simulation that you +are not seeing as well. You can very easily follow the entire process by +turning on all of the logging components in the system. Try setting the +``NS_LOG`` variable to the following, + +:: + + export 'NS_LOG=*=level_all|prefix_func|prefix_time' + +The asterisk above is the logging component wildcard. This will turn on all +of the logging in all of the components used in the simulation. I won't +reproduce the output here (as of this writing it produces 1265 lines of output +for the single packet echo) but you can redirect this information into a file +and look through it with your favorite editor if you like, + +:: + + ./waf --run scratch/myfirst > log.out 2>&1 + +I personally use this extremely verbose version of logging when I am presented +with a problem and I have no idea where things are going wrong. I can follow the +progress of the code quite easily without having to set breakpoints and step +through code in a debugger. I can just edit up the output in my favorite editor +and search around for things I expect, and see things happening that I don't +expect. When I have a general idea about what is going wrong, I transition into +a debugger for a fine-grained examination of the problem. This kind of output +can be especially useful when your script does something completely unexpected. +If you are stepping using a debugger you may miss an unexpected excursion +completely. Logging the excursion makes it quickly visible. + +Adding Logging to your Code ++++++++++++++++++++++++++++ +You can add new logging to your simulations by making calls to the log +component via several macros. Let's do so in the ``myfirst.cc`` script we +have in the ``scratch`` directory. + +Recall that we have defined a logging component in that script: + +:: + + NS_LOG_COMPONENT_DEFINE ("FirstScriptExample"); + +You now know that you can enable all of the logging for this component by +setting the ``NS_LOG`` environment variable to the various levels. Let's +go ahead and add some logging to the script. The macro used to add an +informational level log message is ``NS_LOG_INFO``. Go ahead and add one +(just before we start creating the nodes) that tells you that the script is +"Creating Topology." This is done as in this code snippet, + +Open ``scratch/myfirst.cc`` in your favorite editor and add the line, + +:: + + NS_LOG_INFO ("Creating Topology"); + +right before the lines, + +:: + + NodeContainer nodes; + nodes.Create (2); + +Now build the script using waf and clear the ``NS_LOG`` variable to turn +off the torrent of logging we previously enabled: + +:: + + ./waf + export NS_LOG= + +Now, if you run the script, + +:: + + ./waf --run scratch/myfirst + +you will ``not`` see your new message since its associated logging +component (``FirstScriptExample``) has not been enabled. In order to see your +message you will have to enable the ``FirstScriptExample`` logging component +with a level greater than or equal to ``NS_LOG_INFO``. If you just want to +see this particular level of logging, you can enable it by, + +:: + + export NS_LOG=FirstScriptExample=info + +If you now run the script you will see your new "Creating Topology" log +message, + +:: + + Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' + Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' + 'build' finished successfully (0.404s) + Creating Topology + Sent 1024 bytes to 10.1.1.2 + Received 1024 bytes from 10.1.1.1 + Received 1024 bytes from 10.1.1.2 + +Using Command Line Arguments +**************************** + +Overriding Default Attributes ++++++++++++++++++++++++++++++ +Another way you can change how |ns3| scripts behave without editing +and building is via *command line arguments.* We provide a mechanism to +parse command line arguments and automatically set local and global variables +based on those arguments. + +The first step in using the command line argument system is to declare the +command line parser. This is done quite simply (in your main program) as +in the following code, + +:: + + int + main (int argc, char *argv[]) + { + ... + + CommandLine cmd; + cmd.Parse (argc, argv); + + ... + } + +This simple two line snippet is actually very useful by itself. It opens the +door to the |ns3| global variable and ``Attribute`` systems. Go +ahead and add that two lines of code to the ``scratch/myfirst.cc`` script at +the start of ``main``. Go ahead and build the script and run it, but ask +the script for help in the following way, + +:: + + ./waf --run "scratch/myfirst --PrintHelp" + +This will ask Waf to run the ``scratch/myfirst`` script and pass the command +line argument ``--PrintHelp`` to the script. The quotes are required to +sort out which program gets which argument. The command line parser will +now see the ``--PrintHelp`` argument and respond with, + +:: + + Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' + Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' + 'build' finished successfully (0.413s) + TcpL4Protocol:TcpStateMachine() + CommandLine:HandleArgument(): Handle arg name=PrintHelp value= + --PrintHelp: Print this help message. + --PrintGroups: Print the list of groups. + --PrintTypeIds: Print all TypeIds. + --PrintGroup=[group]: Print all TypeIds of group. + --PrintAttributes=[typeid]: Print all attributes of typeid. + --PrintGlobals: Print the list of globals. + +Let's focus on the ``--PrintAttributes`` option. We have already hinted +at the |ns3| ``Attribute`` system while walking through the +``first.cc`` script. We looked at the following lines of code, + +:: + + PointToPointHelper pointToPoint; + pointToPoint.SetDeviceAttribute ("DataRate", StringValue ("5Mbps")); + pointToPoint.SetChannelAttribute ("Delay", StringValue ("2ms")); + +and mentioned that ``DataRate`` was actually an ``Attribute`` of the +``PointToPointNetDevice``. Let's use the command line argument parser +to take a look at the ``Attributes`` of the PointToPointNetDevice. The help +listing says that we should provide a ``TypeId``. This corresponds to the +class name of the class to which the ``Attributes`` belong. In this case it +will be ``ns3::PointToPointNetDevice``. Let's go ahead and type in, + +:: + + ./waf --run "scratch/myfirst --PrintAttributes=ns3::PointToPointNetDevice" + +The system will print out all of the ``Attributes`` of this kind of net device. +Among the ``Attributes`` you will see listed is, + +:: + + --ns3::PointToPointNetDevice::DataRate=[32768bps]: + The default data rate for point to point links + +This is the default value that will be used when a ``PointToPointNetDevice`` +is created in the system. We overrode this default with the ``Attribute`` +setting in the ``PointToPointHelper`` above. Let's use the default values +for the point-to-point devices and channels by deleting the +``SetDeviceAttribute`` call and the ``SetChannelAttribute`` call from +the ``myfirst.cc`` we have in the scratch directory. + +Your script should now just declare the ``PointToPointHelper`` and not do +any ``set`` operations as in the following example, + +:: + + ... + + NodeContainer nodes; + nodes.Create (2); + + PointToPointHelper pointToPoint; + + NetDeviceContainer devices; + devices = pointToPoint.Install (nodes); + + ... + +Go ahead and build the new script with Waf (``./waf``) and let's go back +and enable some logging from the UDP echo server application and turn on the +time prefix. + +:: + + export 'NS_LOG=UdpEchoServerApplication=level_all|prefix_time' + +If you run the script, you should now see the following output, + +:: + + Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' + Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' + 'build' finished successfully (0.405s) + 0s UdpEchoServerApplication:UdpEchoServer() + 1s UdpEchoServerApplication:StartApplication() + Sent 1024 bytes to 10.1.1.2 + 2.25732s Received 1024 bytes from 10.1.1.1 + 2.25732s Echoing packet + Received 1024 bytes from 10.1.1.2 + 10s UdpEchoServerApplication:StopApplication() + UdpEchoServerApplication:DoDispose() + UdpEchoServerApplication:~UdpEchoServer() + +Recall that the last time we looked at the simulation time at which the packet +was received by the echo server, it was at 2.00369 seconds. + +:: + + 2.00369s UdpEchoServerApplication:HandleRead(): Received 1024 bytes from 10.1.1.1 + +Now it is receiving the packet at 2.25732 seconds. This is because we just dropped +the data rate of the ``PointToPointNetDevice`` down to its default of +32768 bits per second from five megabits per second. + +If we were to provide a new ``DataRate`` using the command line, we could +speed our simulation up again. We do this in the following way, according to +the formula implied by the help item: + +:: + + ./waf --run "scratch/myfirst --ns3::PointToPointNetDevice::DataRate=5Mbps" + +This will set the default value of the ``DataRate`` ``Attribute`` back to +five megabits per second. Are you surprised by the result? It turns out that +in order to get the original behavior of the script back, we will have to set +the speed-of-light delay of the channel as well. We can ask the command line +system to print out the ``Attributes`` of the channel just like we did for +the net device: + +:: + + ./waf --run "scratch/myfirst --PrintAttributes=ns3::PointToPointChannel" + +We discover the ``Delay`` ``Attribute`` of the channel is set in the following +way: + +:: + + --ns3::PointToPointChannel::Delay=[0ns]: + Transmission delay through the channel + +We can then set both of these default values through the command line system, + +:: + + ./waf --run "scratch/myfirst + --ns3::PointToPointNetDevice::DataRate=5Mbps + --ns3::PointToPointChannel::Delay=2ms" + +in which case we recover the timing we had when we explicitly set the +``DataRate`` and ``Delay`` in the script: + +:: + + Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' + Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' + 'build' finished successfully (0.417s) + 0s UdpEchoServerApplication:UdpEchoServer() + 1s UdpEchoServerApplication:StartApplication() + Sent 1024 bytes to 10.1.1.2 + 2.00369s Received 1024 bytes from 10.1.1.1 + 2.00369s Echoing packet + Received 1024 bytes from 10.1.1.2 + 10s UdpEchoServerApplication:StopApplication() + UdpEchoServerApplication:DoDispose() + UdpEchoServerApplication:~UdpEchoServer() + +Note that the packet is again received by the server at 2.00369 seconds. We +could actually set any of the ``Attributes`` used in the script in this way. +In particular we could set the ``UdpEchoClient Attribute MaxPackets`` +to some other value than one. + +How would you go about that? Give it a try. Remember you have to comment +out the place we override the default ``Attribute`` and explicitly set +``MaxPackets`` in the script. Then you have to rebuild the script. You +will also have to find the syntax for actually setting the new default attribute +value using the command line help facility. Once you have this figured out +you should be able to control the number of packets echoed from the command +line. Since we're nice folks, we'll tell you that your command line should +end up looking something like, + +:: + + ./waf --run "scratch/myfirst + --ns3::PointToPointNetDevice::DataRate=5Mbps + --ns3::PointToPointChannel::Delay=2ms + --ns3::UdpEchoClient::MaxPackets=2" + +Hooking Your Own Values ++++++++++++++++++++++++ +You can also add your own hooks to the command line system. This is done +quite simply by using the ``AddValue`` method to the command line parser. + +Let's use this facility to specify the number of packets to echo in a +completely different way. Let's add a local variable called ``nPackets`` +to the ``main`` function. We'll initialize it to one to match our previous +default behavior. To allow the command line parser to change this value, we +need to hook the value into the parser. We do this by adding a call to +``AddValue``. Go ahead and change the ``scratch/myfirst.cc`` script to +start with the following code, + +:: + + int + main (int argc, char *argv[]) + { + uint32_t nPackets = 1; + + CommandLine cmd; + cmd.AddValue("nPackets", "Number of packets to echo", nPackets); + cmd.Parse (argc, argv); + + ... + +Scroll down to the point in the script where we set the ``MaxPackets`` +``Attribute`` and change it so that it is set to the variable ``nPackets`` +instead of the constant ``1`` as is shown below. + +:: + + echoClient.SetAttribute ("MaxPackets", UintegerValue (nPackets)); + +Now if you run the script and provide the ``--PrintHelp`` argument, you +should see your new ``User Argument`` listed in the help display. + +Try, + +:: + + ./waf --run "scratch/myfirst --PrintHelp" + +:: + + Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' + Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' + 'build' finished successfully (0.403s) + --PrintHelp: Print this help message. + --PrintGroups: Print the list of groups. + --PrintTypeIds: Print all TypeIds. + --PrintGroup=[group]: Print all TypeIds of group. + --PrintAttributes=[typeid]: Print all attributes of typeid. + --PrintGlobals: Print the list of globals. + User Arguments: + --nPackets: Number of packets to echo + +If you want to specify the number of packets to echo, you can now do so by +setting the ``--nPackets`` argument in the command line, + +:: + + ./waf --run "scratch/myfirst --nPackets=2" + +You should now see + +:: + + Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' + Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' + 'build' finished successfully (0.404s) + 0s UdpEchoServerApplication:UdpEchoServer() + 1s UdpEchoServerApplication:StartApplication() + Sent 1024 bytes to 10.1.1.2 + 2.25732s Received 1024 bytes from 10.1.1.1 + 2.25732s Echoing packet + Received 1024 bytes from 10.1.1.2 + Sent 1024 bytes to 10.1.1.2 + 3.25732s Received 1024 bytes from 10.1.1.1 + 3.25732s Echoing packet + Received 1024 bytes from 10.1.1.2 + 10s UdpEchoServerApplication:StopApplication() + UdpEchoServerApplication:DoDispose() + UdpEchoServerApplication:~UdpEchoServer() + +You have now echoed two packets. Pretty easy, isn't it? + +You can see that if you are an |ns3| user, you can use the command +line argument system to control global values and ``Attributes``. If you are +a model author, you can add new ``Attributes`` to your ``Objects`` and +they will automatically be available for setting by your users through the +command line system. If you are a script author, you can add new variables to +your scripts and hook them into the command line system quite painlessly. + +Using the Tracing System +************************ + +The whole point of simulation is to generate output for further study, and +the |ns3| tracing system is a primary mechanism for this. Since +|ns3| is a C++ program, standard facilities for generating output +from C++ programs could be used: + +:: + + #include + ... + int main () + { + ... + std::cout << "The value of x is " << x << std::endl; + ... + } + +You could even use the logging module to add a little structure to your +solution. There are many well-known problems generated by such approaches +and so we have provided a generic event tracing subsystem to address the +issues we thought were important. + +The basic goals of the |ns3| tracing system are: + +* For basic tasks, the tracing system should allow the user to generate + standard tracing for popular tracing sources, and to customize which objects + generate the tracing; +* Intermediate users must be able to extend the tracing system to modify + the output format generated, or to insert new tracing sources, without + modifying the core of the simulator; +* Advanced users can modify the simulator core to add new tracing sources + and sinks. + +The |ns3| tracing system is built on the concepts of independent +tracing sources and tracing sinks, and 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. + +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 sink. Trace sinks are consumers of the events and data +provided by the trace sources. For example, one could create a trace sink +that would (when connected to the trace source of the previous example) print +out interesting parts of the received packet. + +The rationale for this explicit division is to allow users to attach new +types of sinks to existing tracing sources, without requiring editing and +recompilation of the core of the simulator. Thus, in the example above, +a user could define a new tracing sink in her script and attach it to an +existing tracing source defined in the simulation core by editing only the +user script. + +In this tutorial, we will walk through some pre-defined sources and sinks and +show how they may be customized with little user effort. See the ns-3 manual +or how-to sections for information on advanced tracing configuration including +extending the tracing namespace and creating new tracing sources. + +ASCII Tracing ++++++++++++++ +|ns3| provides helper functionality that wraps the low-level tracing +system to help you with the details involved in configuring some easily +understood packet traces. If you enable this functionality, you will see +output in a ASCII files --- thus the name. For those familiar with +|ns2| output, this type of trace is analogous to the ``out.tr`` +generated by many scripts. + +Let's just jump right in and add some ASCII tracing output to our +``scratch/myfirst.cc`` script. Right before the call to +``Simulator::Run ()``, add the following lines of code: + +:: + + AsciiTraceHelper ascii; + pointToPoint.EnableAsciiAll (ascii.CreateFileStream ("myfirst.tr")); + +Like in many other |ns3| idioms, this code uses a helper object to +help create ASCII traces. The second line contains two nested method calls. +The "inside" method, ``CreateFileStream()`` uses an unnamed object idiom +to create a file stream object on the stack (without an object name) and pass +it down to the called method. We'll go into this more in the future, but all +you have to know at this point is that you are creating an object representing +a file named "myfirst.tr" and passing it into ``ns-3``. You are telling +``ns-3`` to deal with the lifetime issues of the created object and also to +deal with problems caused by a little-known (intentional) limitation of C++ +ofstream objects relating to copy constructors. + +The outside call, to ``EnableAsciiAll()``, tells the helper that you +want to enable ASCII tracing on all point-to-point devices in your simulation; +and you want the (provided) trace sinks to write out information about packet +movement in ASCII format. + +For those familiar with |ns2|, the traced events are equivalent to +the popular trace points that log "+", "-", "d", and "r" events. + +You can now build the script and run it from the command line: + +:: + + ./waf --run scratch/myfirst + +Just as you have seen many times before, you will see some messages from Waf and then +"'build' finished successfully" with some number of messages from +the running program. + +When it ran, the program will have created a file named ``myfirst.tr``. +Because of the way that Waf works, the file is not created in the local +directory, it is created at the top-level directory of the repository by +default. If you want to control where the traces are saved you can use the +``--cwd`` option of Waf to specify this. We have not done so, thus we +need to change into the top level directory of our repo and take a look at +the ASCII trace file ``myfirst.tr`` in your favorite editor. + +Parsing Ascii Traces +~~~~~~~~~~~~~~~~~~~~ +There's a lot of information there in a pretty dense form, but the first thing +to notice is that there are a number of distinct lines in this file. It may +be difficult to see this clearly unless you widen your window considerably. + +Each line in the file corresponds to a *trace event*. In this case +we are tracing events on the *transmit queue* present in every +point-to-point net device in the simulation. The transmit queue is a queue +through which every packet destined for a point-to-point channel must pass. +Note that each line in the trace file begins with a lone character (has a +space after it). This character will have the following meaning: + +* ``+``: An enqueue operation occurred on the device queue; +* ``-``: A dequeue operation occurred on the device queue; +* ``d``: A packet was dropped, typically because the queue was full; +* ``r``: A packet was received by the net device. + +Let's take a more detailed view of the first line in the trace file. I'll +break it down into sections (indented for clarity) with a two digit reference +number on the left side: + +:: + + 00 + + 01 2 + 02 /NodeList/0/DeviceList/0/$ns3::PointToPointNetDevice/TxQueue/Enqueue + 03 ns3::PppHeader ( + 04 Point-to-Point Protocol: IP (0x0021)) + 05 ns3::Ipv4Header ( + 06 tos 0x0 ttl 64 id 0 protocol 17 offset 0 flags [none] + 07 length: 1052 10.1.1.1 > 10.1.1.2) + 08 ns3::UdpHeader ( + 09 length: 1032 49153 > 9) + 10 Payload (size=1024) + +The first line of this expanded trace event (reference number 00) is the +operation. We have a ``+`` character, so this corresponds to an +*enqueue* operation on the transmit queue. The second line (reference 01) +is the simulation time expressed in seconds. You may recall that we asked the +``UdpEchoClientApplication`` to start sending packets at two seconds. Here +we see confirmation that this is, indeed, happening. + +The next line of the example trace (reference 02) tell us which trace source +originated this event (expressed in the tracing namespace). You can think +of the tracing namespace somewhat like you would a filesystem namespace. The +root of the namespace is the ``NodeList``. This corresponds to a container +managed in the |ns3| core code that contains all of the nodes that are +created in a script. Just as a filesystem may have directories under the +root, we may have node numbers in the ``NodeList``. The string +``/NodeList/0`` therefore refers to the zeroth node in the ``NodeList`` +which we typically think of as "node 0". In each node there is a list of +devices that have been installed. This list appears next in the namespace. +You can see that this trace event comes from ``DeviceList/0`` which is the +zeroth device installed in the node. + +The next string, ``$ns3::PointToPointNetDevice`` tells you what kind of +device is in the zeroth position of the device list for node zero. +Recall that the operation ``+`` found at reference 00 meant that an enqueue +operation happened on the transmit queue of the device. This is reflected in +the final segments of the "trace path" which are ``TxQueue/Enqueue``. + +The remaining lines in the trace should be fairly intuitive. References 03-04 +indicate that the packet is encapsulated in the point-to-point protocol. +References 05-07 show that the packet has an IP version four header and has +originated from IP address 10.1.1.1 and is destined for 10.1.1.2. References +08-09 show that this packet has a UDP header and, finally, reference 10 shows +that the payload is the expected 1024 bytes. + +The next line in the trace file shows the same packet being dequeued from the +transmit queue on the same node. + +The Third line in the trace file shows the packet being received by the net +device on the node with the echo server. I have reproduced that event below. + +:: + + 00 r + 01 2.25732 + 02 /NodeList/1/DeviceList/0/$ns3::PointToPointNetDevice/MacRx + 03 ns3::Ipv4Header ( + 04 tos 0x0 ttl 64 id 0 protocol 17 offset 0 flags [none] + 05 length: 1052 10.1.1.1 > 10.1.1.2) + 06 ns3::UdpHeader ( + 07 length: 1032 49153 > 9) + 08 Payload (size=1024) + +Notice that the trace operation is now ``r`` and the simulation time has +increased to 2.25732 seconds. If you have been following the tutorial steps +closely this means that you have left the ``DataRate`` of the net devices +and the channel ``Delay`` set to their default values. This time should +be familiar as you have seen it before in a previous section. + +The trace source namespace entry (reference 02) has changed to reflect that +this event is coming from node 1 (``/NodeList/1``) and the packet reception +trace source (``/MacRx``). It should be quite easy for you to follow the +progress of the packet through the topology by looking at the rest of the +traces in the file. + +PCAP Tracing +++++++++++++ +The |ns3| device helpers can also be used to create trace files in the +``.pcap`` format. The acronym pcap (usually written in lower case) stands +for packet capture, and is actually an API that includes the +definition of a ``.pcap`` file format. The most popular program that can +read and display this format is Wireshark (formerly called Ethereal). +However, there are many traffic trace analyzers that use this packet format. +We encourage users to exploit the many tools available for analyzing pcap +traces. In this tutorial, we concentrate on viewing pcap traces with tcpdump. + +The code used to enable pcap tracing is a one-liner. + +:: + + pointToPoint.EnablePcapAll ("myfirst"); + +Go ahead and insert this line of code after the ASCII tracing code we just +added to ``scratch/myfirst.cc``. Notice that we only passed the string +"myfirst," and not "myfirst.pcap" or something similar. This is because the +parameter is a prefix, not a complete file name. The helper will actually +create a trace file for every point-to-point device in the simulation. The +file names will be built using the prefix, the node number, the device number +and a ".pcap" suffix. + +In our example script, we will eventually see files named "myfirst-0-0.pcap" +and "myfirst-1-0.pcap" which are the pcap traces for node 0-device 0 and +node 1-device 0, respectively. + +Once you have added the line of code to enable pcap tracing, you can run the +script in the usual way: + +:: + + ./waf --run scratch/myfirst + +If you look at the top level directory of your distribution, you should now +see three log files: ``myfirst.tr`` is the ASCII trace file we have +previously examined. ``myfirst-0-0.pcap`` and ``myfirst-1-0.pcap`` +are the new pcap files we just generated. + +Reading output with tcpdump +~~~~~~~~~~~~~~~~~~~~~~~~~~~ +The easiest thing to do at this point will be to use ``tcpdump`` to look +at the ``pcap`` files. + +:: + + tcpdump -nn -tt -r myfirst-0-0.pcap + reading from file myfirst-0-0.pcap, link-type PPP (PPP) + 2.000000 IP 10.1.1.1.49153 > 10.1.1.2.9: UDP, length 1024 + 2.514648 IP 10.1.1.2.9 > 10.1.1.1.49153: UDP, length 1024 + + tcpdump -nn -tt -r myfirst-1-0.pcap + reading from file myfirst-1-0.pcap, link-type PPP (PPP) + 2.257324 IP 10.1.1.1.49153 > 10.1.1.2.9: UDP, length 1024 + 2.257324 IP 10.1.1.2.9 > 10.1.1.1.49153: UDP, length 1024 + +You can see in the dump of ``myfirst-0-0.pcap`` (the client device) that the +echo packet is sent at 2 seconds into the simulation. If you look at the +second dump (``myfirst-1-0.pcap``) you can see that packet being received +at 2.257324 seconds. You see the packet being echoed back at 2.257324 seconds +in the second dump, and finally, you see the packet being received back at +the client in the first dump at 2.514648 seconds. + +Reading output with Wireshark +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +If you are unfamiliar with Wireshark, there is a web site available from which +you can download programs and documentation: http://www.wireshark.org/. + +Wireshark is a graphical user interface which can be used for displaying these +trace files. If you have Wireshark available, you can open each of the trace +files and display the contents as if you had captured the packets using a +*packet sniffer*. diff -r c9133c87760d -r 7ff69b244b5b doc/tutorial/tracing.texi --- 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 - ... - 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 - - 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 () - .AddTraceSource ("MyInteger", - "An integer value to trace.", - MakeTraceSourceAccessor (&MyObject::m_myInt)) - ; - return tid; - } - - MyObject () {} - TracedValue 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 = CreateObject (); - 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 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 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 which we -used to call GetId() on. We could have used this Ptr directly to call -a connect method directly: - -@verbatim - Ptr 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 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 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} 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 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 = node->GetObject () -@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 > 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 () - .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 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 > 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}. -This tells you that you need a function that returns void and takes a -a @code{Ptr}. For example, - -@verbatim - void - CourseChangeCallback (Ptr 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 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 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 > 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::TracedCallback () - TracedCallback::ConnectWithoutContext (c ... - TracedCallback::Connect (const CallbackB ... - TracedCallback::DisconnectWithoutContext ... - TracedCallback::Disconnect (const Callba ... - TracedCallback::operator() (void) const ... - TracedCallback::operator() (T1 a1) const ... - TracedCallback::operator() (T1 a1, T2 a2 ... - TracedCallback::operator() (T1 a1, T2 a2 ... - TracedCallback::operator() (T1 a1, T2 a2 ... - TracedCallback::operator() (T1 a1, T2 a2 ... - TracedCallback::operator() (T1 a1, T2 a2 ... - TracedCallback::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 - 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 > m_courseChangeTrace; -@end verbatim - -The @code{typename T1} in the templated class declaration corresponds to the -@code{Ptr} 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 - void - TracedCallback::ConnectWithoutContext ... - { - Callback 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}. - -@verbatim - void - TracedCallback::ConnectWithoutContext ... cb - { - Callback > 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 > 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} -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}. For example, - -@verbatim - void - CourseChangeCallback (Ptr 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 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 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} 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 - 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 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} which -will correspond to a @code{TracedCallback} 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 () - .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 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 - #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, 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 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, 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} 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 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 = Create (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 (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 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 >}. 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} -- 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 em = CreateObjectWithAttributes ( - "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 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 app = CreateObject (); - 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 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 file, Ptr 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} 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}) 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 stream = asciiTraceHelper.CreateFileStream ("sixth.cwnd"); - ns3TcpSocket->TraceConnectWithoutContext ("CongestionWindow", MakeBoundCallback (&CwndChange, stream)); - - ... - - PcapHelper pcapHelper; - Ptr 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 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 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 file ... - Ptr stream ... -@end verbatim - -The underlying objects are entirely different. For example, the -Ptr 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, 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 -@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 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 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 stream = asciiTraceHelper.CreateFileStream ("sixth.cwnd"); - ns3TcpSocket->TraceConnectWithoutContext ("CongestionWindow", MakeBoundCallback (&CwndChange, stream)); - - ... - - static void - RxDrop (Ptr file, Ptr p) - { - NS_LOG_UNCOND ("RxDrop at " << Simulator::Now ().GetSeconds ()); - file->Write(Simulator::Now(), p); - } - - ... - - PcapHelper pcapHelper; - Ptr 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 --- 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 --- 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 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 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 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 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} to an @code{EnablePcap} method. The @code{Ptr} is -implicit since the net device must belong to exactly one @code{Node}. -For example, - -@verbatim - Ptr 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} is looked up from the name -string. Again, the @code 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 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 ``--.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 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 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 stream, - std::string prefix, - Ptr 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 nd, bool explicitFilename = false); - void EnableAscii (Ptr stream, Ptr 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 nd, bool explicitFilename = false); - void EnableAscii (Ptr stream, Ptr nd); - - void EnableAscii (std::string prefix, std::string ndName, bool explicitFilename = false); - void EnableAscii (Ptr stream, std::string ndName); - - void EnableAscii (std::string prefix, NetDeviceContainer d); - void EnableAscii (Ptr stream, NetDeviceContainer d); - - void EnableAscii (std::string prefix, NodeContainer n); - void EnableAscii (Ptr stream, NodeContainer n); - - void EnableAsciiAll (std::string prefix); - void EnableAsciiAll (Ptr stream); - - void EnableAscii (std::string prefix, uint32_t nodeid, uint32_t deviceid, bool explicitFilename); - void EnableAscii (Ptr 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 -- 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} to an @code{EnableAscii} -method. The @code{Ptr} is implicit since the net device must belong to -exactly one @code{Node}. For example, - -@verbatim - Ptr 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 nd1; - Ptr nd2; - ... - Ptr 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} is looked up from the name -string. Again, the @code 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 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 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 --.tr convention. Combining all of the -traces into a single file is accomplished similarly to the examples above: - -@verbatim - NetDeviceContainer d = ...; - ... - Ptr 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 --.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 --.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 ``--.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} instead of a -@code{Ptr} 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, - 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, 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, 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} and @code{interface} to an @code{EnablePcap} method. For example, - -@verbatim - Ptr ipv4 = node->GetObject (); - ... - 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} 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} 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 -``--.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 -"-n-i.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 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} instead of a -@code{Ptr} 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 stream, - std::string prefix, - Ptr 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, uint32_t interface, bool explicitFilename = false); - void EnableAsciiIpv4 (Ptr stream, Ptr 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, uint32_t interface, bool explicitFilename = false); - void EnableAsciiIpv4 (Ptr stream, Ptr ipv4, uint32_t interface); - - void EnableAsciiIpv4 (std::string prefix, std::string ipv4Name, uint32_t interface, bool explicitFilename = false); - void EnableAsciiIpv4 (Ptr stream, std::string ipv4Name, uint32_t interface); - - void EnableAsciiIpv4 (std::string prefix, Ipv4InterfaceContainer c); - void EnableAsciiIpv4 (Ptr stream, Ipv4InterfaceContainer c); - - void EnableAsciiIpv4 (std::string prefix, NodeContainer n); - void EnableAsciiIpv4 (Ptr stream, NodeContainer n); - - void EnableAsciiIpv4All (std::string prefix); - void EnableAsciiIpv4All (Ptr stream); - - void EnableAsciiIpv4 (std::string prefix, uint32_t nodeid, uint32_t deviceid, bool explicitFilename); - void EnableAsciiIpv4 (Ptr 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 -n- -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} and an @code{interface} -to an @code{EnableAscii} method. -For example, - -@verbatim - Ptr 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 protocol1 = node1->GetObject (); - Ptr protocol2 = node2->GetObject (); - ... - Ptr 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} is looked up from the name -string. The @code 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 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 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 -n-i.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 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 --.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} 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 -n-i--.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 diff -r c9133c87760d -r 7ff69b244b5b doc/tutorial/tutorial.css --- a/doc/tutorial/tutorial.css Sun Jan 02 22:57:04 2011 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,156 +0,0 @@ -body { - font-family: "Trebuchet MS", "Bitstream Vera Sans", verdana, lucida, arial, helvetica, sans-serif; - background: white; - color: black; - font-size: 11pt; -} - -h1, h2, h3, h4, h5, h6 { -# color: #990000; - color: #009999; -} - -pre { - font-size: 10pt; - background: #e0e0e0; - color: black; -} - -a:link, a:visited { - font-weight: normal; - text-decoration: none; - color: #0047b9; -} - -a:hover { - font-weight: normal; - text-decoration: underline; - color: #0047b9; -} - -img { - border: 0px; -} - -#main th { - font-size: 12pt; - background: #b0b0b0; -} - -.odd { - font-size: 12pt; - background: white; -} - -.even { - font-size: 12pt; - background: #e0e0e0; -} - -.answer { - font-size: large; - font-weight: bold; -} - -.answer p { - font-size: 12pt; - font-weight: normal; -} - -.answer ul { - font-size: 12pt; - font-weight: normal; -} - -#container { - position: absolute; - width: 100%; - height: 100%; - top: 0px; -} - -#feedback { - color: #b0b0b0; - font-size: 9pt; - font-style: italic; -} - -#header { - position: absolute; - margin: 0px; - top: 10px; - height:96px; - left: 175px; - right: 10em; - bottom: auto; - background: white; - clear: both; -} - -#middle { - position: absolute; - left: 0; - height: auto; - width: 100%; -} - -#main { - position: absolute; - top: 50px; - left: 175px; - right: 100px; - background: white; - padding: 0em 0em 0em 0em; -} - -#navbar { - position: absolute; - top: 75px; - left: 0em; - width: 146px; - padding: 0px; - margin: 0px; - font-size: 10pt; -} - -#navbar a:link, #navbar a:visited { - font-weight: normal; - text-decoration: none; - color: #0047b9; -} - -#navbar a:hover { - font-weight: normal; - text-decoration: underline; - color: #0047b9; -} - -#navbar dl { - width: 146px; - padding: 0; - margin: 0 0 10px 0px; - background: #99ffff url(images/box_bottom2.gif) no-repeat bottom left; -} - -#navbar dt { - padding: 6px 10px; - font-size: 100%; - font-weight: bold; - background: #009999; - margin: 0px; - border-bottom: 1px solid #fff; - color: white; - background: #009999 url(images/box_top2.gif) no-repeat top left; -} - -#navbar dd { - font-size: 100%; - margin: 0 0 0 0px; - padding: 6px 10px; - color: #0047b9; -} - -dd#selected { - background: #99ffff url(images/arrow.gif) no-repeat; - background-position: 4px 10px; -} diff -r c9133c87760d -r 7ff69b244b5b doc/tutorial/tutorial.texi --- a/doc/tutorial/tutorial.texi Sun Jan 02 22:57:04 2011 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,106 +0,0 @@ -\input texinfo @c -*-texinfo-*- -@c %**start of header -@setfilename ns-3.info -@settitle ns-3 tutorial -@c @setchapternewpage odd -@c %**end of header - -@ifinfo -Primary documentation for the @command{ns-3} project is available in -four forms: -@itemize @bullet -@item @uref{http://www.nsnam.org/doxygen/index.html,,ns-3 Doxygen/Manual}: Documentation of the public APIs of the simulator -@item Tutorial (this document) -@item @uref{http://www.nsnam.org/docs/manual.html,,Reference Manual}: Reference Manual -@item @uref{http://www.nsnam.org/wiki/index.php,, ns-3 wiki} -@end itemize - -This document is written in GNU Texinfo and is to be maintained in revision -control on the @command{ns-3} code server. Both PDF and HTML versions should -be available on the server. Changes to the document should be discussed on -the ns-developers@@isi.edu mailing list. -@end ifinfo - -@copying - -This is an @command{ns-3} tutorial. -Primary documentation for the @command{ns-3} project is available in -four forms: -@itemize @bullet -@item @uref{http://www.nsnam.org/doxygen/index.html,,ns-3 Doxygen/Manual}: Documentation of the public APIs of the simulator -@item Tutorial (this document) -@item @uref{http://www.nsnam.org/docs/manual.html,,Reference Manual}: Reference Manual -@item @uref{http://www.nsnam.org/wiki/index.php,, ns-3 wiki} -@end itemize - -This document is written in GNU Texinfo and is to be maintained in revision -control on the @command{ns-3} code server. Both PDF and HTML versions should -be available on the server. Changes to the document should be discussed on -the ns-developers@@isi.edu mailing list. - -This software is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This software 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, see @uref{http://www.gnu.org/licenses/}. -@end copying - -@titlepage -@title ns-3 Tutorial -@author ns-3 project -@author feedback: ns-developers@@isi.edu -@today{} - -@c @page -@vskip 0pt plus 1filll -@insertcopying -@end titlepage - -@c So the toc is printed at the start. -@ifnottex -@anchor{Full Table of Contents} -@end ifnottex -@contents - -@ifnottex -@node Top, Introduction, Full Table of Contents -@top ns-3 Tutorial (html version) - -For a pdf version of this tutorial, -see @uref{http://www.nsnam.org/docs/tutorial.pdf}. - -@insertcopying -@end ifnottex - -@menu -* Introduction:: -* Resources:: -* Getting Started:: -* Conceptual Overview:: -* Tweaking ns-3:: -* Building Topologies:: -* The Tracing System:: -* Closing Remarks:: -* Index:: -@end menu - -@include introduction.texi -@include getting-started.texi -@include conceptual-overview.texi -@include tweaking.texi -@include building-topologies.texi -@include tracing.texi -@include conclusion.texi - -@node Index -@unnumbered Index -@printindex cp - -@bye diff -r c9133c87760d -r 7ff69b244b5b doc/tutorial/tweaking.texi --- a/doc/tutorial/tweaking.texi Sun Jan 02 22:57:04 2011 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1046 +0,0 @@ - -@c ======================================================================== -@c Begin document body here -@c ======================================================================== - -@c ======================================================================== -@c PART: Tweaking ns-3 -@c ======================================================================== -@c The below chapters are under the major heading "Tweaking ns-3" -@c This is similar to the Latex \part command -@c -@c ======================================================================== -@c Tweaking ns-3 -@c ======================================================================== -@node Tweaking ns-3 -@chapter Tweaking ns-3 - -@menu -* Using the Logging Module:: -* Using Command Line Arguments:: -* Using the Tracing System:: -@end menu - -@c ======================================================================== -@c Using the Logging Module -@c ======================================================================== -@node Using the Logging Module -@section Using the Logging Module - -@cindex logging -We have already taken a brief look at the @command{ns-3} logging module while -going over the @code{first.cc} script. We will now take a closer look and -see what kind of use-cases the logging subsystem was designed to cover. - -@node Logging Overview -@subsection Logging Overview -Many large systems support some kind of message logging facility, and -@command{ns-3} is not an exception. In some cases, only error messages are -logged to the ``operator console'' (which is typically @code{stderr} in Unix- -based systems). In other systems, warning messages may be output as well as -more detailed informational messages. In some cases, logging facilities are -used to output debug messages which can quickly turn the output into a blur. - -@command{Ns-3} takes the view that all of these verbosity levels are useful -and we provide a selectable, multi-level approach to message logging. Logging -can be disabled completely, enabled on a component-by-component basis, or -enabled globally; and it provides selectable verbosity levels. The -@command{ns-3} log module provides a straightforward, relatively easy to use -way to get useful information out of your simulation. - -You should understand that we do provide a general purpose mechanism --- -tracing --- to get data out of your models which should be preferred for -simulation output (see the tutorial section Using the Tracing System for -more details on our tracing system). Logging should be preferred for -debugging information, warnings, error messages, or any time you want to -easily get a quick message out of your scripts or models. - -There are currently seven levels of log messages of increasing verbosity -defined in the system. - -@itemize @bullet -@item NS_LOG_ERROR --- Log error messages; -@item NS_LOG_WARN --- Log warning messages; -@item NS_LOG_DEBUG --- Log relatively rare, ad-hoc debugging messages; -@item NS_LOG_INFO --- Log informational messages about program progress; -@item NS_LOG_FUNCTION --- Log a message describing each function called; -@item NS_LOG_LOGIC -- Log messages describing logical flow within a function; -@item NS_LOG_ALL --- Log everything. -@end itemize - -We also provide an unconditional logging level that is always displayed, -irrespective of logging levels or component selection. - -@itemize @bullet -@item NS_LOG_UNCOND -- Log the associated message unconditionally. -@end itemize - -Each level can be requested singly or cumulatively; and logging can be set -up using a shell environment variable (NS_LOG) or by logging system function -call. As was seen earlier in the tutorial, the logging system has Doxygen -documentation and now would be a good time to peruse the Logging Module -documentation if you have not done so. - -Now that you have read the documentation in great detail, let's use some of -that knowledge to get some interesting information out of the -@code{scratch/myfirst.cc} example script you have already built. - -@node Enabling Logging -@subsection Enabling Logging -@cindex NS_LOG -Let's use the NS_LOG environment variable to turn on some more logging, but -first, just to get our bearings, go ahead and run the last script just as you -did previously, - -@verbatim - ./waf --run scratch/myfirst -@end verbatim - -You should see the now familiar output of the first @command{ns-3} example -program - -@verbatim - Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' - Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' - 'build' finished successfully (0.413s) - Sent 1024 bytes to 10.1.1.2 - Received 1024 bytes from 10.1.1.1 - Received 1024 bytes from 10.1.1.2 -@end verbatim - -It turns out that the ``Sent'' and ``Received'' messages you see above are -actually logging messages from the @code{UdpEchoClientApplication} and -@code{UdpEchoServerApplication}. We can ask the client application, for -example, to print more information by setting its logging level via the -NS_LOG environment variable. - -I am going to assume from here on that you are using an sh-like shell that uses -the``VARIABLE=value'' syntax. If you are using a csh-like shell, then you -will have to convert my examples to the ``setenv VARIABLE value'' syntax -required by those shells. - -Right now, the UDP echo client application is responding to the following line -of code in @code{scratch/myfirst.cc}, - -@verbatim - LogComponentEnable("UdpEchoClientApplication", LOG_LEVEL_INFO); -@end verbatim - -This line of code enables the @code{LOG_LEVEL_INFO} level of logging. When -we pass a logging level flag, we are actually enabling the given level and -all lower levels. In this case, we have enabled @code{NS_LOG_INFO}, -@code{NS_LOG_DEBUG}, @code{NS_LOG_WARN} and @code{NS_LOG_ERROR}. We can -increase the logging level and get more information without changing the -script and recompiling by setting the NS_LOG environment variable like this: - -@verbatim - export NS_LOG=UdpEchoClientApplication=level_all -@end verbatim - -This sets the shell environment variable @code{NS_LOG} to the string, - -@verbatim - UdpEchoClientApplication=level_all -@end verbatim - -The left hand side of the assignment is the name of the logging component we -want to set, and the right hand side is the flag we want to use. In this case, -we are going to turn on all of the debugging levels for the application. If -you run the script with NS_LOG set this way, the @command{ns-3} logging -system will pick up the change and you should see the following output: - -@verbatim - Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build - Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' - 'build' finished successfully (0.404s) - UdpEchoClientApplication:UdpEchoClient() - UdpEchoClientApplication:SetDataSize(1024) - UdpEchoClientApplication:StartApplication() - UdpEchoClientApplication:ScheduleTransmit() - UdpEchoClientApplication:Send() - Sent 1024 bytes to 10.1.1.2 - Received 1024 bytes from 10.1.1.1 - UdpEchoClientApplication:HandleRead(0x6241e0, 0x624a20) - Received 1024 bytes from 10.1.1.2 - UdpEchoClientApplication:StopApplication() - UdpEchoClientApplication:DoDispose() - UdpEchoClientApplication:~UdpEchoClient() -@end verbatim - -The additional debug information provided by the application is from -the NS_LOG_FUNCTION level. This shows every time a function in the application -is called during script execution. Note that there are no requirements in the -@command{ns-3} system that models must support any particular logging -functionality. The decision regarding how much information is logged -is left to the individual model developer. In the case of the echo -applications, a good deal of log output is available. - -You can now see a log of the function calls that were made to the application. -If you look closely you will notice a single colon between the string -@code{UdpEchoClientApplication} and the method name where you might have -expected a C++ scope operator (@code{::}). This is intentional. - -The name is not actually a class name, it is a logging component name. When -there is a one-to-one correspondence between a source file and a class, this -will generally be the class name but you should understand that it is not -actually a class name, and there is a single colon there instead of a double -colon to remind you in a relatively subtle way to conceptually separate the -logging component name from the class name. - -It turns out that in some cases, it can be hard to determine which method -actually generates a log message. If you look in the text above, you may -wonder where the string ``@code{Received 1024 bytes from 10.1.1.2}'' comes -from. You can resolve this by OR'ing the @code{prefix_func} level into the -@code{NS_LOG} environment variable. Try doing the following, - -@verbatim - export 'NS_LOG=UdpEchoClientApplication=level_all|prefix_func' -@end verbatim - -Note that the quotes are required since the vertical bar we use to indicate an -OR operation is also a Unix pipe connector. - -Now, if you run the script you will see that the logging system makes sure -that every message from the given log component is prefixed with the component -name. - -@verbatim - Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' - Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' - 'build' finished successfully (0.417s) - UdpEchoClientApplication:UdpEchoClient() - UdpEchoClientApplication:SetDataSize(1024) - UdpEchoClientApplication:StartApplication() - UdpEchoClientApplication:ScheduleTransmit() - UdpEchoClientApplication:Send() - UdpEchoClientApplication:Send(): Sent 1024 bytes to 10.1.1.2 - Received 1024 bytes from 10.1.1.1 - UdpEchoClientApplication:HandleRead(0x6241e0, 0x624a20) - UdpEchoClientApplication:HandleRead(): Received 1024 bytes from 10.1.1.2 - UdpEchoClientApplication:StopApplication() - UdpEchoClientApplication:DoDispose() - UdpEchoClientApplication:~UdpEchoClient() -@end verbatim - -You can now see all of the messages coming from the UDP echo client application -are identified as such. The message ``Received 1024 bytes from 10.1.1.2'' is -now clearly identified as coming from the echo client application. The -remaining message must be coming from the UDP echo server application. We -can enable that component by entering a colon separated list of components in -the NS_LOG environment variable. - -@verbatim - export 'NS_LOG=UdpEchoClientApplication=level_all|prefix_func: - UdpEchoServerApplication=level_all|prefix_func' -@end verbatim - -Warning: You will need to remove the newline after the @code{:} in the -example text above which is only there for document formatting purposes. - -Now, if you run the script you will see all of the log messages from both the -echo client and server applications. You may see that this can be very useful -in debugging problems. - -@verbatim - Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' - Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' - 'build' finished successfully (0.406s) - UdpEchoServerApplication:UdpEchoServer() - UdpEchoClientApplication:UdpEchoClient() - UdpEchoClientApplication:SetDataSize(1024) - UdpEchoServerApplication:StartApplication() - UdpEchoClientApplication:StartApplication() - UdpEchoClientApplication:ScheduleTransmit() - UdpEchoClientApplication:Send() - UdpEchoClientApplication:Send(): Sent 1024 bytes to 10.1.1.2 - UdpEchoServerApplication:HandleRead(): Received 1024 bytes from 10.1.1.1 - UdpEchoServerApplication:HandleRead(): Echoing packet - UdpEchoClientApplication:HandleRead(0x624920, 0x625160) - UdpEchoClientApplication:HandleRead(): Received 1024 bytes from 10.1.1.2 - UdpEchoServerApplication:StopApplication() - UdpEchoClientApplication:StopApplication() - UdpEchoClientApplication:DoDispose() - UdpEchoServerApplication:DoDispose() - UdpEchoClientApplication:~UdpEchoClient() - UdpEchoServerApplication:~UdpEchoServer() -@end verbatim - -It is also sometimes useful to be able to see the simulation time at which a -log message is generated. You can do this by ORing in the prefix_time bit. - -@verbatim - export 'NS_LOG=UdpEchoClientApplication=level_all|prefix_func|prefix_time: - UdpEchoServerApplication=level_all|prefix_func|prefix_time' -@end verbatim - -Again, you will have to remove the newline above. If you run the script now, -you should see the following output: - -@verbatim - Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' - Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' - 'build' finished successfully (0.418s) - 0s UdpEchoServerApplication:UdpEchoServer() - 0s UdpEchoClientApplication:UdpEchoClient() - 0s UdpEchoClientApplication:SetDataSize(1024) - 1s UdpEchoServerApplication:StartApplication() - 2s UdpEchoClientApplication:StartApplication() - 2s UdpEchoClientApplication:ScheduleTransmit() - 2s UdpEchoClientApplication:Send() - 2s UdpEchoClientApplication:Send(): Sent 1024 bytes to 10.1.1.2 - 2.00369s UdpEchoServerApplication:HandleRead(): Received 1024 bytes from 10.1.1.1 - 2.00369s UdpEchoServerApplication:HandleRead(): Echoing packet - 2.00737s UdpEchoClientApplication:HandleRead(0x624290, 0x624ad0) - 2.00737s UdpEchoClientApplication:HandleRead(): Received 1024 bytes from 10.1.1.2 - 10s UdpEchoServerApplication:StopApplication() - 10s UdpEchoClientApplication:StopApplication() - UdpEchoClientApplication:DoDispose() - UdpEchoServerApplication:DoDispose() - UdpEchoClientApplication:~UdpEchoClient() - UdpEchoServerApplication:~UdpEchoServer() -@end verbatim - -You can see that the constructor for the UdpEchoServer was called at a -simulation time of 0 seconds. This is actually happening before the -simulation starts, but the time is displayed as zero seconds. The same is true -for the UdpEchoClient constructor message. - -Recall that the @code{scratch/first.cc} script started the echo server -application at one second into the simulation. You can now see that the -@code{StartApplication} method of the server is, in fact, called at one second. -You can also see that the echo client application is started at a simulation -time of two seconds as we requested in the script. - -You can now follow the progress of the simulation from the -@code{ScheduleTransmit} call in the client that calls @code{Send} to the -@code{HandleRead} callback in the echo server application. Note that the -elapsed time for the packet to be sent across the point-to-point link is 3.69 -milliseconds. You see the echo server logging a message telling you that it -has echoed the packet and then, after another channel delay, you see the echo -client receive the echoed packet in its @code{HandleRead} method. - -There is a lot that is happening under the covers in this simulation that you -are not seeing as well. You can very easily follow the entire process by -turning on all of the logging components in the system. Try setting the -@code{NS_LOG} variable to the following, - -@verbatim - export 'NS_LOG=*=level_all|prefix_func|prefix_time' -@end verbatim - -The asterisk above is the logging component wildcard. This will turn on all -of the logging in all of the components used in the simulation. I won't -reproduce the output here (as of this writing it produces 1265 lines of output -for the single packet echo) but you can redirect this information into a file -and look through it with your favorite editor if you like, - -@verbatim - ./waf --run scratch/myfirst > log.out 2>&1 -@end verbatim - -I personally use this extremely verbose version of logging when I am presented -with a problem and I have no idea where things are going wrong. I can follow the -progress of the code quite easily without having to set breakpoints and step -through code in a debugger. I can just edit up the output in my favorite editor -and search around for things I expect, and see things happening that I don't -expect. When I have a general idea about what is going wrong, I transition into -a debugger for a fine-grained examination of the problem. This kind of output -can be especially useful when your script does something completely unexpected. -If you are stepping using a debugger you may miss an unexpected excursion -completely. Logging the excursion makes it quickly visible. - -@node Adding Logging to your Code -@subsection Adding Logging to your Code -@cindex NS_LOG -You can add new logging to your simulations by making calls to the log -component via several macros. Let's do so in the @code{myfirst.cc} script we -have in the @code{scratch} directory. - -Recall that we have defined a logging component in that script: - -@verbatim - NS_LOG_COMPONENT_DEFINE ("FirstScriptExample"); -@end verbatim - -You now know that you can enable all of the logging for this component by -setting the @code{NS_LOG} environment variable to the various levels. Let's -go ahead and add some logging to the script. The macro used to add an -informational level log message is @code{NS_LOG_INFO}. Go ahead and add one -(just before we start creating the nodes) that tells you that the script is -``Creating Topology.'' This is done as in this code snippet, - -Open @code{scratch/myfirst.cc} in your favorite editor and add the line, - -@verbatim - NS_LOG_INFO ("Creating Topology"); -@end verbatim - -right before the lines, - -@verbatim - NodeContainer nodes; - nodes.Create (2); -@end verbatim - -Now build the script using waf and clear the @code{NS_LOG} variable to turn -off the torrent of logging we previously enabled: - -@verbatim - ./waf - export NS_LOG= -@end verbatim - -Now, if you run the script, - -@verbatim - ./waf --run scratch/myfirst -@end verbatim - -you will @emph{not} see your new message since its associated logging -component (@code{FirstScriptExample}) has not been enabled. In order to see your -message you will have to enable the @code{FirstScriptExample} logging component -with a level greater than or equal to @code{NS_LOG_INFO}. If you just want to -see this particular level of logging, you can enable it by, - -@verbatim - export NS_LOG=FirstScriptExample=info -@end verbatim - -If you now run the script you will see your new ``Creating Topology'' log -message, - -@verbatim - Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' - Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' - 'build' finished successfully (0.404s) - Creating Topology - Sent 1024 bytes to 10.1.1.2 - Received 1024 bytes from 10.1.1.1 - Received 1024 bytes from 10.1.1.2 -@end verbatim - -@c ======================================================================== -@c Using Command Line Arguments -@c ======================================================================== -@node Using Command Line Arguments -@section Using Command Line Arguments - -@subsection Overriding Default Attributes -@cindex command line arguments -Another way you can change how @command{ns-3} scripts behave without editing -and building is via @emph{command line arguments.} We provide a mechanism to -parse command line arguments and automatically set local and global variables -based on those arguments. - -The first step in using the command line argument system is to declare the -command line parser. This is done quite simply (in your main program) as -in the following code, - -@verbatim - int - main (int argc, char *argv[]) - { - ... - - CommandLine cmd; - cmd.Parse (argc, argv); - - ... - } -@end verbatim - -This simple two line snippet is actually very useful by itself. It opens the -door to the @command{ns-3} global variable and @code{Attribute} systems. Go -ahead and add that two lines of code to the @code{scratch/myfirst.cc} script at -the start of @code{main}. Go ahead and build the script and run it, but ask -the script for help in the following way, - -@verbatim - ./waf --run "scratch/myfirst --PrintHelp" -@end verbatim - -This will ask Waf to run the @code{scratch/myfirst} script and pass the command -line argument @code{--PrintHelp} to the script. The quotes are required to -sort out which program gets which argument. The command line parser will -now see the @code{--PrintHelp} argument and respond with, - -@verbatim - Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' - Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' - 'build' finished successfully (0.413s) - TcpL4Protocol:TcpStateMachine() - CommandLine:HandleArgument(): Handle arg name=PrintHelp value= - --PrintHelp: Print this help message. - --PrintGroups: Print the list of groups. - --PrintTypeIds: Print all TypeIds. - --PrintGroup=[group]: Print all TypeIds of group. - --PrintAttributes=[typeid]: Print all attributes of typeid. - --PrintGlobals: Print the list of globals. -@end verbatim - -Let's focus on the @code{--PrintAttributes} option. We have already hinted -at the @command{ns-3} @code{Attribute} system while walking through the -@code{first.cc} script. We looked at the following lines of code, - -@verbatim - PointToPointHelper pointToPoint; - pointToPoint.SetDeviceAttribute ("DataRate", StringValue ("5Mbps")); - pointToPoint.SetChannelAttribute ("Delay", StringValue ("2ms")); -@end verbatim - -and mentioned that @code{DataRate} was actually an @code{Attribute} of the -@code{PointToPointNetDevice}. Let's use the command line argument parser -to take a look at the @code{Attributes} of the PointToPointNetDevice. The help -listing says that we should provide a @code{TypeId}. This corresponds to the -class name of the class to which the @code{Attributes} belong. In this case it -will be @code{ns3::PointToPointNetDevice}. Let's go ahead and type in, - -@verbatim - ./waf --run "scratch/myfirst --PrintAttributes=ns3::PointToPointNetDevice" -@end verbatim - -The system will print out all of the @code{Attributes} of this kind of net device. -Among the @code{Attributes} you will see listed is, - -@verbatim - --ns3::PointToPointNetDevice::DataRate=[32768bps]: - The default data rate for point to point links -@end verbatim - -This is the default value that will be used when a @code{PointToPointNetDevice} -is created in the system. We overrode this default with the @code{Attribute} -setting in the @code{PointToPointHelper} above. Let's use the default values -for the point-to-point devices and channels by deleting the -@code{SetDeviceAttribute} call and the @code{SetChannelAttribute} call from -the @code{myfirst.cc} we have in the scratch directory. - -Your script should now just declare the @code{PointToPointHelper} and not do -any @code{set} operations as in the following example, - -@verbatim - ... - - NodeContainer nodes; - nodes.Create (2); - - PointToPointHelper pointToPoint; - - NetDeviceContainer devices; - devices = pointToPoint.Install (nodes); - - ... -@end verbatim - -Go ahead and build the new script with Waf (@code{./waf}) and let's go back -and enable some logging from the UDP echo server application and turn on the -time prefix. - -@verbatim - export 'NS_LOG=UdpEchoServerApplication=level_all|prefix_time' -@end verbatim - -If you run the script, you should now see the following output, - -@verbatim - Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' - Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' - 'build' finished successfully (0.405s) - 0s UdpEchoServerApplication:UdpEchoServer() - 1s UdpEchoServerApplication:StartApplication() - Sent 1024 bytes to 10.1.1.2 - 2.25732s Received 1024 bytes from 10.1.1.1 - 2.25732s Echoing packet - Received 1024 bytes from 10.1.1.2 - 10s UdpEchoServerApplication:StopApplication() - UdpEchoServerApplication:DoDispose() - UdpEchoServerApplication:~UdpEchoServer() -@end verbatim - -Recall that the last time we looked at the simulation time at which the packet -was received by the echo server, it was at 2.00369 seconds. - -@verbatim - 2.00369s UdpEchoServerApplication:HandleRead(): Received 1024 bytes from 10.1.1.1 -@end verbatim - -Now it is receiving the packet at 2.25732 seconds. This is because we just dropped -the data rate of the @code{PointToPointNetDevice} down to its default of -32768 bits per second from five megabits per second. - -If we were to provide a new @code{DataRate} using the command line, we could -speed our simulation up again. We do this in the following way, according to -the formula implied by the help item: - -@verbatim - ./waf --run "scratch/myfirst --ns3::PointToPointNetDevice::DataRate=5Mbps" -@end verbatim - -This will set the default value of the @code{DataRate} @code{Attribute} back to -five megabits per second. Are you surprised by the result? It turns out that -in order to get the original behavior of the script back, we will have to set -the speed-of-light delay of the channel as well. We can ask the command line -system to print out the @code{Attributes} of the channel just like we did for -the net device: - -@verbatim - ./waf --run "scratch/myfirst --PrintAttributes=ns3::PointToPointChannel" -@end verbatim - -We discover the @code{Delay} @code{Attribute} of the channel is set in the following -way: - -@verbatim - --ns3::PointToPointChannel::Delay=[0ns]: - Transmission delay through the channel -@end verbatim - -We can then set both of these default values through the command line system, - -@verbatim - ./waf --run "scratch/myfirst - --ns3::PointToPointNetDevice::DataRate=5Mbps - --ns3::PointToPointChannel::Delay=2ms" -@end verbatim - -in which case we recover the timing we had when we explicitly set the -@code{DataRate} and @code{Delay} in the script: - -@verbatim - Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' - Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' - 'build' finished successfully (0.417s) - 0s UdpEchoServerApplication:UdpEchoServer() - 1s UdpEchoServerApplication:StartApplication() - Sent 1024 bytes to 10.1.1.2 - 2.00369s Received 1024 bytes from 10.1.1.1 - 2.00369s Echoing packet - Received 1024 bytes from 10.1.1.2 - 10s UdpEchoServerApplication:StopApplication() - UdpEchoServerApplication:DoDispose() - UdpEchoServerApplication:~UdpEchoServer() -@end verbatim - -Note that the packet is again received by the server at 2.00369 seconds. We -could actually set any of the @code{Attributes} used in the script in this way. -In particular we could set the @code{UdpEchoClient Attribute MaxPackets} -to some other value than one. - -How would you go about that? Give it a try. Remember you have to comment -out the place we override the default @code{Attribute} and explicitly set -@code{MaxPackets} in the script. Then you have to rebuild the script. You -will also have to find the syntax for actually setting the new default attribute -value using the command line help facility. Once you have this figured out -you should be able to control the number of packets echoed from the command -line. Since we're nice folks, we'll tell you that your command line should -end up looking something like, - -@verbatim - ./waf --run "scratch/myfirst - --ns3::PointToPointNetDevice::DataRate=5Mbps - --ns3::PointToPointChannel::Delay=2ms - --ns3::UdpEchoClient::MaxPackets=2" -@end verbatim - -@subsection Hooking Your Own Values -You can also add your own hooks to the command line system. This is done -quite simply by using the @code{AddValue} method to the command line parser. - -Let's use this facility to specify the number of packets to echo in a -completely different way. Let's add a local variable called @code{nPackets} -to the @code{main} function. We'll initialize it to one to match our previous -default behavior. To allow the command line parser to change this value, we -need to hook the value into the parser. We do this by adding a call to -@code{AddValue}. Go ahead and change the @code{scratch/myfirst.cc} script to -start with the following code, - -@verbatim - int - main (int argc, char *argv[]) - { - uint32_t nPackets = 1; - - CommandLine cmd; - cmd.AddValue("nPackets", "Number of packets to echo", nPackets); - cmd.Parse (argc, argv); - - ... -@end verbatim - -Scroll down to the point in the script where we set the @code{MaxPackets} -@code{Attribute} and change it so that it is set to the variable @code{nPackets} -instead of the constant @code{1} as is shown below. - -@verbatim - echoClient.SetAttribute ("MaxPackets", UintegerValue (nPackets)); -@end verbatim - -Now if you run the script and provide the @code{--PrintHelp} argument, you -should see your new @code{User Argument} listed in the help display. - -Try, - -@verbatim - ./waf --run "scratch/myfirst --PrintHelp" -@end verbatim - -@verbatim - Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' - Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' - 'build' finished successfully (0.403s) - --PrintHelp: Print this help message. - --PrintGroups: Print the list of groups. - --PrintTypeIds: Print all TypeIds. - --PrintGroup=[group]: Print all TypeIds of group. - --PrintAttributes=[typeid]: Print all attributes of typeid. - --PrintGlobals: Print the list of globals. - User Arguments: - --nPackets: Number of packets to echo -@end verbatim - -If you want to specify the number of packets to echo, you can now do so by -setting the @code{--nPackets} argument in the command line, - -@verbatim - ./waf --run "scratch/myfirst --nPackets=2" -@end verbatim - -You should now see - -@verbatim - Waf: Entering directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' - Waf: Leaving directory `/home/craigdo/repos/ns-3-allinone/ns-3-dev/build' - 'build' finished successfully (0.404s) - 0s UdpEchoServerApplication:UdpEchoServer() - 1s UdpEchoServerApplication:StartApplication() - Sent 1024 bytes to 10.1.1.2 - 2.25732s Received 1024 bytes from 10.1.1.1 - 2.25732s Echoing packet - Received 1024 bytes from 10.1.1.2 - Sent 1024 bytes to 10.1.1.2 - 3.25732s Received 1024 bytes from 10.1.1.1 - 3.25732s Echoing packet - Received 1024 bytes from 10.1.1.2 - 10s UdpEchoServerApplication:StopApplication() - UdpEchoServerApplication:DoDispose() - UdpEchoServerApplication:~UdpEchoServer() -@end verbatim - -You have now echoed two packets. Pretty easy, isn't it? - -You can see that if you are an @command{ns-3} user, you can use the command -line argument system to control global values and @code{Attributes}. If you are -a model author, you can add new @code{Attributes} to your @code{Objects} and -they will automatically be available for setting by your users through the -command line system. If you are a script author, you can add new variables to -your scripts and hook them into the command line system quite painlessly. - -@c ======================================================================== -@c Using the Tracing System -@c ======================================================================== -@node Using the Tracing System -@section Using the Tracing System - -The whole point of simulation is to generate output for further study, and -the @command{ns-3} tracing system is a primary mechanism for this. Since -@command{ns-3} is a C++ program, standard facilities for generating output -from C++ programs could be used: - -@verbatim - #include - ... - int main () - { - ... - std::cout << "The value of x is " << x << std::endl; - ... - } -@end verbatim - -You could even use the logging module to add a little structure to your -solution. There are many well-known problems generated by such approaches -and so we have provided a generic event tracing subsystem to address the -issues we thought were important. - -The basic goals of the @command{ns-3} tracing system are: - -@itemize @bullet -@item For basic tasks, the tracing system should allow the user to generate -standard tracing for popular tracing sources, and to customize which objects -generate the tracing; -@item Intermediate users must be able to extend the tracing system to modify -the output format generated, or to insert new tracing sources, without -modifying the core of the simulator; -@item Advanced users can modify the simulator core to add new tracing sources -and sinks. -@end itemize - -The @command{ns-3} tracing system is built on the concepts of independent -tracing sources and tracing sinks, and 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. - -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 sink. Trace sinks are consumers of the events and data -provided by the trace sources. For example, one could create a trace sink -that would (when connected to the trace source of the previous example) print -out interesting parts of the received packet. - -The rationale for this explicit division is to allow users to attach new -types of sinks to existing tracing sources, without requiring editing and -recompilation of the core of the simulator. Thus, in the example above, -a user could define a new tracing sink in her script and attach it to an -existing tracing source defined in the simulation core by editing only the -user script. - -In this tutorial, we will walk through some pre-defined sources and sinks and -show how they may be customized with little user effort. See the ns-3 manual -or how-to sections for information on advanced tracing configuration including -extending the tracing namespace and creating new tracing sources. - -@cindex tracing -@cindex ASCII tracing -@subsection ASCII Tracing -@command{Ns-3} provides helper functionality that wraps the low-level tracing -system to help you with the details involved in configuring some easily -understood packet traces. If you enable this functionality, you will see -output in a ASCII files --- thus the name. For those familiar with -@command{ns-2} output, this type of trace is analogous to the @command{out.tr} -generated by many scripts. - -@cindex tracing packets -Let's just jump right in and add some ASCII tracing output to our -@code{scratch/myfirst.cc} script. Right before the call to -@code{Simulator::Run ()}, add the following lines of code: - -@verbatim - AsciiTraceHelper ascii; - pointToPoint.EnableAsciiAll (ascii.CreateFileStream ("myfirst.tr")); -@end verbatim - -Like in many other @command{ns-3} idioms, this code uses a helper object to -help create ASCII traces. The second line contains two nested method calls. -The ``inside'' method, @code{CreateFileStream()} uses an unnamed object idiom -to create a file stream object on the stack (without an object name) and pass -it down to the called method. We'll go into this more in the future, but all -you have to know at this point is that you are creating an object representing -a file named ``myfirst.tr'' and passing it into @code{ns-3}. You are telling -@code{ns-3} to deal with the lifetime issues of the created object and also to -deal with problems caused by a little-known (intentional) limitation of C++ -ofstream objects relating to copy constructors. - -The outside call, to @code{EnableAsciiAll()}, tells the helper that you -want to enable ASCII tracing on all point-to-point devices in your simulation; -and you want the (provided) trace sinks to write out information about packet -movement in ASCII format. - -For those familiar with @command{ns-2}, the traced events are equivalent to -the popular trace points that log "+", "-", "d", and "r" events. - -You can now build the script and run it from the command line: - -@verbatim - ./waf --run scratch/myfirst -@end verbatim - -@cindex myfirst.tr -Just as you have seen many times before, you will see some messages from Waf and then -``'build' finished successfully'' with some number of messages from -the running program. - -When it ran, the program will have created a file named @code{myfirst.tr}. -Because of the way that Waf works, the file is not created in the local -directory, it is created at the top-level directory of the repository by -default. If you want to control where the traces are saved you can use the -@code{--cwd} option of Waf to specify this. We have not done so, thus we -need to change into the top level directory of our repo and take a look at -the ASCII trace file @code{myfirst.tr} in your favorite editor. - -@subsubsection Parsing Ascii Traces -@cindex parsing ascii traces -There's a lot of information there in a pretty dense form, but the first thing -to notice is that there are a number of distinct lines in this file. It may -be difficult to see this clearly unless you widen your window considerably. - -Each line in the file corresponds to a @emph{trace event}. In this case -we are tracing events on the @emph{transmit queue} present in every -point-to-point net device in the simulation. The transmit queue is a queue -through which every packet destined for a point-to-point channel must pass. -Note that each line in the trace file begins with a lone character (has a -space after it). This character will have the following meaning: - -@cindex ascii trace enqueue operation -@cindex ascii trace dequeue operation -@cindex ascii trace drop operation -@cindex ascii trace receive operation -@itemize @bullet -@item @code{+}: An enqueue operation occurred on the device queue; -@item @code{-}: A dequeue operation occurred on the device queue; -@item @code{d}: A packet was dropped, typically because the queue was full; -@item @code{r}: A packet was received by the net device. -@end itemize - -Let's take a more detailed view of the first line in the trace file. I'll -break it down into sections (indented for clarity) with a two digit reference -number on the left side: - -@verbatim - 00 + - 01 2 - 02 /NodeList/0/DeviceList/0/$ns3::PointToPointNetDevice/TxQueue/Enqueue - 03 ns3::PppHeader ( - 04 Point-to-Point Protocol: IP (0x0021)) - 05 ns3::Ipv4Header ( - 06 tos 0x0 ttl 64 id 0 protocol 17 offset 0 flags [none] - 07 length: 1052 10.1.1.1 > 10.1.1.2) - 08 ns3::UdpHeader ( - 09 length: 1032 49153 > 9) - 10 Payload (size=1024) -@end verbatim - -@cindex trace event -@cindex simulation time -The first line of this expanded trace event (reference number 00) is the -operation. We have a @code{+} character, so this corresponds to an -@emph{enqueue} operation on the transmit queue. The second line (reference 01) -is the simulation time expressed in seconds. You may recall that we asked the -@code{UdpEchoClientApplication} to start sending packets at two seconds. Here -we see confirmation that this is, indeed, happening. - -@cindex node number -@cindex net device number -@cindex smart pointer -The next line of the example trace (reference 02) tell us which trace source -originated this event (expressed in the tracing namespace). You can think -of the tracing namespace somewhat like you would a filesystem namespace. The -root of the namespace is the @code{NodeList}. This corresponds to a container -managed in the @command{ns-3} core code that contains all of the nodes that are -created in a script. Just as a filesystem may have directories under the -root, we may have node numbers in the @code{NodeList}. The string -@code{/NodeList/0} therefore refers to the zeroth node in the @code{NodeList} -which we typically think of as ``node 0''. In each node there is a list of -devices that have been installed. This list appears next in the namespace. -You can see that this trace event comes from @code{DeviceList/0} which is the -zeroth device installed in the node. - -The next string, @code{$ns3::PointToPointNetDevice} tells you what kind of -device is in the zeroth position of the device list for node zero. -Recall that the operation @code{+} found at reference 00 meant that an enqueue -operation happened on the transmit queue of the device. This is reflected in -the final segments of the ``trace path'' which are @code{TxQueue/Enqueue}. - -The remaining lines in the trace should be fairly intuitive. References 03-04 -indicate that the packet is encapsulated in the point-to-point protocol. -References 05-07 show that the packet has an IP version four header and has -originated from IP address 10.1.1.1 and is destined for 10.1.1.2. References -08-09 show that this packet has a UDP header and, finally, reference 10 shows -that the payload is the expected 1024 bytes. - -The next line in the trace file shows the same packet being dequeued from the -transmit queue on the same node. - -The Third line in the trace file shows the packet being received by the net -device on the node with the echo server. I have reproduced that event below. - -@verbatim - 00 r - 01 2.25732 - 02 /NodeList/1/DeviceList/0/$ns3::PointToPointNetDevice/MacRx - 03 ns3::Ipv4Header ( - 04 tos 0x0 ttl 64 id 0 protocol 17 offset 0 flags [none] - 05 length: 1052 10.1.1.1 > 10.1.1.2) - 06 ns3::UdpHeader ( - 07 length: 1032 49153 > 9) - 08 Payload (size=1024) -@end verbatim - -Notice that the trace operation is now @code{r} and the simulation time has -increased to 2.25732 seconds. If you have been following the tutorial steps -closely this means that you have left the @code{DataRate} of the net devices -and the channel @code{Delay} set to their default values. This time should -be familiar as you have seen it before in a previous section. - -The trace source namespace entry (reference 02) has changed to reflect that -this event is coming from node 1 (@code{/NodeList/1}) and the packet reception -trace source (@code{/MacRx}). It should be quite easy for you to follow the -progress of the packet through the topology by looking at the rest of the -traces in the file. - -@subsection PCAP Tracing -@cindex pcap -@cindex Wireshark -The @command{ns-3} device helpers can also be used to create trace files in the -@code{.pcap} format. The acronym pcap (usually written in lower case) stands -for @emph{p}acket @emph{cap}ture, and is actually an API that includes the -definition of a @code{.pcap} file format. The most popular program that can -read and display this format is Wireshark (formerly called Ethereal). -However, there are many traffic trace analyzers that use this packet format. -We encourage users to exploit the many tools available for analyzing pcap -traces. In this tutorial, we concentrate on viewing pcap traces with tcpdump. - -@cindex pcap tracing -The code used to enable pcap tracing is a one-liner. - -@verbatim - pointToPoint.EnablePcapAll ("myfirst"); -@end verbatim - -Go ahead and insert this line of code after the ASCII tracing code we just -added to @code{scratch/myfirst.cc}. Notice that we only passed the string -``myfirst,'' and not ``myfirst.pcap'' or something similar. This is because the -parameter is a prefix, not a complete file name. The helper will actually -create a trace file for every point-to-point device in the simulation. The -file names will be built using the prefix, the node number, the device number -and a ``.pcap'' suffix. - -In our example script, we will eventually see files named ``myfirst-0-0.pcap'' -and ``myfirst-1-0.pcap'' which are the pcap traces for node 0-device 0 and -node 1-device 0, respectively. - -Once you have added the line of code to enable pcap tracing, you can run the -script in the usual way: - -@verbatim - ./waf --run scratch/myfirst -@end verbatim - -If you look at the top level directory of your distribution, you should now -see three log files: @code{myfirst.tr} is the ASCII trace file we have -previously examined. @code{myfirst-0-0.pcap} and @code{myfirst-1-0.pcap} -are the new pcap files we just generated. - -@subsubsection Reading output with tcpdump -@cindex tcpdump -The easiest thing to do at this point will be to use @code{tcpdump} to look -at the @code{pcap} files. - -@verbatim - tcpdump -nn -tt -r myfirst-0-0.pcap - reading from file myfirst-0-0.pcap, link-type PPP (PPP) - 2.000000 IP 10.1.1.1.49153 > 10.1.1.2.9: UDP, length 1024 - 2.514648 IP 10.1.1.2.9 > 10.1.1.1.49153: UDP, length 1024 - - tcpdump -nn -tt -r myfirst-1-0.pcap - reading from file myfirst-1-0.pcap, link-type PPP (PPP) - 2.257324 IP 10.1.1.1.49153 > 10.1.1.2.9: UDP, length 1024 - 2.257324 IP 10.1.1.2.9 > 10.1.1.1.49153: UDP, length 1024 -@end verbatim - -You can see in the dump of @code{myfirst-0-0.pcap} (the client device) that the -echo packet is sent at 2 seconds into the simulation. If you look at the -second dump (@code{myfirst-1-0.pcap}) you can see that packet being received -at 2.257324 seconds. You see the packet being echoed back at 2.257324 seconds -in the second dump, and finally, you see the packet being received back at -the client in the first dump at 2.514648 seconds. - -@subsubsection Reading output with Wireshark -@cindex Wireshark -If you are unfamiliar with Wireshark, there is a web site available from which -you can download programs and documentation: @uref{http://www.wireshark.org/}. - -Wireshark is a graphical user interface which can be used for displaying these -trace files. If you have Wireshark available, you can open each of the trace -files and display the contents as if you had captured the packets using a -@emph{packet sniffer}.