Printable version of this document
Emulab Tutorial - A More Advanced Example
Here is a slightly more complex example demonstrating the use of RED
queues, traffic generation, and the event system. Where possible, we
adhere to the syntax and operational model of
ns-2, as described in the
NS manual.
- RED/GRED Queues: In addition to normal DropTail links, Emulab
supports the specification of the RED and GRED (Gentle RED) links
in your NS file. RED/GRED queuing is handled via the
insertion of a traffic shaping delay node, in much the same way
that bandwidth, delay, and packet loss is handled. For a better
understanding of how we support traffic shaping, see the
ipfw and dummynet man pages on
users.emulab.net. It is important to note that Emulab
supports a smaller set of tunable parameters then NS does; please
read the aforementioned manual pages!
- Traffic Generation: Emulab supports Constant Bit Rate (CBR)
traffic generation, in conjunction with either Agent/UDP or
Agent/TCP agents. We currently use the
TG Tool Set to generate
traffic.
- Traffic Generation using
NS Emulation (NSE): Emulab supports TCP traffic generation
using NS's Agent/TCP/FullTcp which is a BSD Reno derivative and
its subclasses namely Newreno, Tahoe and Sack. Currently two
application classes are supported: Application/FTP and
Application/Telnet. The former drives the FullTcp agent to send
bulk-data according to connection dynamics. The latter uses the
NS's
tcplib telnet distribution for telnet-like data. For
configuration parameters and commands allowed on the objects,
refer to NS documentation
here.
- Event System: Emulab supports limited use of the NS at
syntax, allowing you to define a static set of events in your NS
file, to be delivered to agents running on your nodes. There is
also "dynamic events" support that can be used to inject events
into the system on the fly, say from a script running on
users.emulab.net.
- Program Objects: Emulab has added extensions that allow you to
run arbitrary programs on your nodes, starting and stopping them
at any point during your experiment run.
What follows is a sample NS file that
demonstrates the above features, with annotations where appropriate.
First we define the 2 nodes in the topology:
set nodeA [$ns node]
set nodeB [$ns node]
Next define a duplex link between nodes nodeA and nodeB. Instead of a
standard DropTail link, it is declared to be a Random Early Detection
(RED) link. While this is obviously contrived, it allows us to ignore
routing issues within this
example.
set link0 [$ns duplex-link $nodeA $nodeB 100Mb 0ms RED]
Each link is has an NS "Queue" object associated with it, which you
can modify to suit your needs (currently, there are two queue
objects per duplex link; one for each direction. You need to set the
parameters for both directions, which means you can set the parameters
asymmetrically if you want). The following parameters can be
changed, and are defined in the NS manual (see Section 7.3).
set queue0 [[$ns link $nodeA $nodeB] queue]
$queue0 set gentle_ 0
$queue0 set red_ 0
$queue0 set queue-in-bytes_ 0
$queue0 set limit_ 50
$queue0 set maxthresh_ 15
$queue0 set thresh_ 5
$queue0 set linterm_ 10
$queue0 set q_weight_ 0.002
In the case of a LAN, there is a single queue object for every node
that is a member of the LAN and it refers to the node-to-lan direction.
The only special case is a 100Mb 0ms LAN that does not use
end node shaping.
No queue object is available in that case. Here is an example
that illustrates how to get handles on the queue objects of a LAN
so as to change the parameters:
set n0 [$ns node]
set n1 [$ns node]
set n2 [$ns node]
set lan0 [$ns make-lan "$n0 $n1 $n2" 100Mb 0ms]
set q0 [[$ns lanlink $lan0 $n0] queue]
set q1 [[$ns lanlink $lan0 $n1] queue]
set q2 [[$ns lanlink $lan0 $n2] queue]
$q0 set limit_ 20
...
A UDP agent is created and attached to nodeA, then a CBR traffic
generator application is created, and attached to the UDP agent:
set udp0 [new Agent/UDP]
$ns attach-agent $nodeA $udp0
set cbr0 [new Application/Traffic/CBR]
$cbr0 set packetSize_ 500
$cbr0 set interval_ 0.005
$cbr0 attach-agent $udp0
A TCP agent is created and also attached to nodeA, then a second CBR
traffic generator application is created, and attached to the TCP
agent:
set tcp0 [new Agent/TCP]
$ns attach-agent $nodeA $tcp0
set cbr1 [new Application/Traffic/CBR]
$cbr1 set packetSize_ 500
$cbr1 set interval_ 0.005
$cbr1 attach-agent $tcp0
You must define traffic sinks for each of the traffic generators
created above. The sinks are attached to nodeB:
set null0 [new Agent/Null]
$ns attach-agent $nodeB $null0
set null1 [new Agent/TCPSink]
$ns attach-agent $nodeB $null1
Then you must connect the traffic generators on nodeA to the traffic sinks
on nodeB:
$ns connect $udp0 $null0
$ns connect $tcp0 $null1
Here is a good example for NSE FullTcp traffic generation. The
following code snippet attaches an FTP agent that drives a Reno
FullTcp on NodeA:
set tcpfull0 [new Agent/TCP/FullTcp]
$ns attach-agent $nodeA $tcpfull0
set ftp0 [new Application/FTP]
$ftp0 attach-agent $tcpfull0
You must then define the sink FullTcp endpoint and call the method
"listen" making this agent wait for an incoming connection:
set tcpfull1 [new Agent/TCP/FullTcp/Sack]
$tcpfull1 listen
$ns attach-agent $nodeB $tcpfull1
Like all other source-sink traffic generators, you need to connect
them:
$ns connect $tcpfull0 $tcpfull1
Lastly, a set of events to control your applications and link
characteristics:
$ns at 60.0 "$cbr0 start"
$ns at 70.0 "$link0 bandwidth 10Mb duplex"
$ns at 80.0 "$link0 delay 10ms"
$ns at 90.0 "$link0 plr 0.05"
$ns at 100.0 "$link0 down"
$ns at 110.0 "$link0 up"
$ns at 115.0 "$cbr0 stop"
$ns at 120.0 "$ftp0 start"
$ns at 140.0 "$tcpfull0 set segsize_ 256; $tcpfull0 set segsperack_ 2"
$ns at 145.0 "$tcpfull1 set nodelay_ true"
$ns at 150.0 "$ftp0 stop"
$ns at 120.0 "$cbr1 start"
$ns at 130.0 "$cbr1 set packetSize_ 512"
$ns at 130.0 "$cbr1 set interval_ 0.01"
$ns at 140.0 "$link0 down"
$ns at 150.0 "$cbr1 stop"
When you receive email containing the experiment setup information (as
described in Beginning an
Experiment), you will notice an additonal section that gives a
summary of the events that will be delivered during your experiment:
Event Summary:
--------------
Event count: 18
First event: 60.000 seconds
Last event: 160.000 seconds
You can get a full listing of the events for your experiment by running
tbreport -v proj expt on users.emulab.net. This
report will include a section like this:
Event List:
Time Node Agent Type Event Arguments
------------ ------------ ---------- ---------- ---------- ------------
60.000 nodeA cbr0 TRAFGEN START PACKETSIZE=500
RATE=100000
INTERVAL=0.005
70.000 tbsdelay0 link0 LINK MODIFY BANDWIDTH=10000
80.000 tbsdelay0 link0 LINK MODIFY DELAY=10ms
90.000 tbsdelay0 link0 LINK MODIFY PLR=0.05
100.000 tbsdelay0 link0 LINK DOWN
110.000 tbsdelay0 link0 LINK UP
115.000 nodeA cbr0 TRAFGEN STOP
120.000 nodeA cbr1 TRAFGEN START PACKETSIZE=500
RATE=100000
INTERVAL=0.005
120.000 nodeA ftp0 TRAFGEN MODIFY $ftp0 start
130.000 nodeA cbr1 TRAFGEN MODIFY PACKETSIZE=512
130.000 nodeA cbr1 TRAFGEN MODIFY INTERVAL=0.01
140.000 tbsdelay0 link0 LINK DOWN
140.000 nodeA tcpfull0 TRAFGEN MODIFY $tcpfull0 set segsize_ 256
140.000 nodeA tcpfull0 TRAFGEN MODIFY $tcpfull0 set segsperack_ 2
145.000 nodeB tcpfull1 TRAFGEN MODIFY $tcpfull1 set nodelay_ true
150.000 tbsdelay0 link0 LINK UP
150.000 nodeA ftp0 TRAFGEN MODIFY $ftp0 stop
160.000 nodeA cbr1 TRAFGEN STOP
The above list represents the set of events for your experiments, and
are stored in the Emulab Database. When your experiment is swapped in,
an event scheduler is started that will process the list, and
send them at the time offset specified. In order to make sure that all
of the nodes are actually rebooted and ready, time does not start
ticking until all of the nodes have reported to the event system that
they are ready. At present, events are restricted to system level
agents (Emulab traffic generators and delay nodes), but in the future
we expect to provide an API that will allow experimentors to write
their own event agents.
Dynamic Scheduling of Events
NS scripts give you the ability to schedule events dynamically; an NS
script is just a TCL program and the argument to the "at" command is
any valid TCL expression. This gives you great flexibility in a
simulated world, but alas, this cannot be supported in a practical
manner in the real world. Instead, we provide a way for you to inject
events into the system dynamically, but leave it up to you to script
those events in whatever manner you are most comfortable with, be it a
PERL script, or a shell script, or even another TCL script! Dynamic
event injection is accomplished via the Testbed Event Client
(tevc), which is installed on your experimental nodes and on
users.emulab.net. The command line syntax for tevc
is:
tevc -e proj/expt time objname event [args ...]
where the time parameter is one of:
- now
- +seconds (floating point or integer)
- [[[[yy]mm]dd]HH]MMss
For example, you could issue this sequence of events.
tevc -e testbed/myexp now cbr0 set interval_=0.2
tevc -e testbed/myexp +10 cbr0 start
tevc -e testbed/myexp +15 link0 down
tevc -e testbed/myexp +17 link0 up
tevc -e testbed/myexp +20 cbr0 stop
Some points worth mentioning:
- There is no "global" clock; Emulab nodes are kept in sync with
NTP, which does a very good job of keeping all of the clocks
within 1ms of each other.
- The times "now" and "+seconds" are relative to the time at which
each event is submitted, not to each other or the start of the
experiment.
- The set of events you can send is currently limited to control of
traffic generators and delay nodes. We expect to add more agents
in the future.
- Sending dynamic events that intermix with statically scheduled events
can result in unpredictable behavior if you are not careful.
- Currently, the event list is replayed each time the experiment is
swapped in. This is almost certainly not the behaviour people
expect; we plan to change that very soon.
- tevc does not provide any feedback; if you specify an
object (say, cbr78 or link45) that is not a valid object in your
experiment, the event is silently thrown away. Further, if you
specify an operation or parameter that is not approprate (say,
"link0 start" instead of "link0 up"), the event is silently
dropped. We expect to add error feedback in the future.
Supported Events
This is a (mostly) comprehensive list of events that you can specify,
either in your NS file or as a dynamic event on the command line. In
the listings below, the use of "link0", "cbr0", etc. are included to
clarify the syntax; the actual object names will depend on your NS
file. Also note that when sending events from the command line with
tevc, you should not include the dollar ($) sign. For
example:
| NS File: |
$ns at 3.0 "$link0 down" |
| tevc: |
tevc -e proj/expt +3.0 link0 down
|
- Links:
In "ns" script:
$link0 bandwidth 10Mb duplex
$link0 delay 10ms
$link0 plr 0.05
With "tevc":
tevc ... link0 modify bandwidth=20000 # In kbits/second; 20000 = 20Mbps
tevc ... link0 modify delay=10ms # In msecs (the "ms" is ignoredd)
tevc ... link0 modify plr=0.1
Both:
$link0 up
$link0 down
- Queues: Queues are special. In your NS file you modify the actual
queue, while on the command line you use the link to which the queue belongs.
$queue0 set queue-in-bytes_ 0
$queue0 set limit_ 75
$queue0 set maxthresh_ 20
$queue0 set thresh_ 7
$queue0 set linterm_ 11
$queue0 set q_weight_ 0.004
- CBR: interval_ and rate_ are two way of specifying the same thing.
iptos_ allows you to set the IP_TOS socket option for a traffic
stream.
$cbr0 start
$cbr0 set packetSize_ 512
$cbr0 set interval_ 0.01
$cbr0 set rate_ 10Mb
$cbr0 set iptos_ 16
$cbr0 stop
- FullTcp, FTP and Telnet: Refer to the NS documentation here.
Event Groups
Event Groups allow you to conveniently send events to groups of like
objects. For example, if you want to bring down a set of links at the
same time, you could do it one event at a time:
$ns at 100.0 "$link0 down"
$ns at 100.0 "$link1 down"
$ns at 100.0 "$link2 down"
$ns at 100.0 "$link3 down"
which works, but is somewhat verbose. Its also presents a problem when
sending dynamic events with tevc from the shell:
tevc -e proj/expt now link0 down
tevc -e proj/expt now link1 down
tevc -e proj/expt now link2 down
tevc -e proj/expt now link3 down
These four events will be separated by many milliseconds as each call
to tevc requires forking a command from the shell, contacting boss,
sending the event to the event scheduler, etc.
A better alternative is to create an event group, which will
schedule events for all of the members of the group, sending them at
the same time from the event scheduler. The example above can be more
simply implemented as:
set mylinks [new EventGroup $ns]
$mylinks add $link0 $link1 $link2 $link3
$ns at 60.0 "$mylinks down"
From the command line:
tevc -e proj/expt now mylinks down
Note:
- All of the members of an event group must be of the same type;
you cannot, say, put a link and a program object into the same
event group since they respond to entirely different commands.
The parser will reject such groups.
- An object (such as a link or lan) can be in multiple event
groups.
- Event groups are not hierarchical; you cannot put one event group
into another event group. If you need this functionality, then
you need to put the objects themselves (such as a link or lan)
into each event group directly:
set mylinks1 [new EventGroup $ns]
set mylinks2 [new EventGroup $ns]
$mylinks1 add $link0 $link1 $link2 $link3
$mylinks2 add $link0 $link1 $link2 $link3
Program Objects
We have added some extensions that allow you to use NS's at
syntax to invoke arbitrary commands on your experimental nodes. Once
you define a program object and initialize its command line and the
node on which the command should be run, you can schedule the command
to be started and stopped with NS at statements. To define a
program object:
set prog0 [new Program $ns]
$prog0 set node $nodeA
$prog0 set command "/bin/ls -lt >& /users/joe/logs/prog0"
set prog1 [new Program $ns]
$prog1 set node $nodeB
$prog1 set command "/bin/sleep 60 >& /tmp/sleep.debug"
Then in your NS file a set of static events to run these commands:
$ns at 10 "$prog0 start"
$ns at 20 "$prog1 start"
$ns at 30 "$prog1 stop"
If you want to schedule starts and stops using dynamic events:
tevc -e testbed/myexp now prog0 start
tevc -e testbed/myexp now prog1 start
tevc -e testbed/myexp +20 prog1 stop
If you want to change the command that is run (override the command
you specified in your NS file), then:
tevc -e testbed/myexp now prog0 start COMMAND='ls >/tmp/foo'
Some points worth mentioning:
- A program must be "stopped" before it is started; if the program
is currently running on the node, the start event will be
silently ignored.
- The command line is passed to /bin/csh; any valid csh expression
is allowed, although no syntax checking is done prior to invoking
it. If the syntax is bad, the command will fail. It is a good
idea to redirect output to a log file so you can track failures.
- The "stop" command is implemented by sending a SIGTERM to the
process group leader (the csh process). If the SIGTERM fails, a
SIGKILL is sent.
|