1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370
|
\chapter{PLM}
{\sloppy
\label{sec:PLM}
This chapter describes the ns implementation of the PLM protocol
\cite{legout_sigmetrics2000}. The code of the PLM
protocol is written in both C++ and OTcl. The PLM Packet Pair generator is
written in C++ and the PLM core machinery is written in OTcl. The chapter has simply
three parts: the first part shows how to create and configure a PLM session; the
second part describes the Packet Pair source generator; the third part describes
the architecture and internals of the PLM protocol. In this last part, rather
than giving a list of procedures and functions, we introduce the main
procedures per functionality (instantiation of a PLM source, instantiation of a
PLM receiver, reception of a packet, detection of a loss, etc.).
The procedures, functions, and variables described in this chapter can be found in:
\nsf{plm/cbr-traffic-PP.cc}, \nsf{plm/loss-monitor-plm.cc}, \nsf{tcl/plm/plm.tcl},
\nsf{tcl/plm/plm-ns.tcl}, \nsf{tcl/plm/plm-topo.tcl}, \nsf{tcl/lib/ns-default.tcl}.
\section{Configuration}
\label{sec:Configuration}
\paragraph{Creating a simple scenario with one PLM flow (only one receiver)\\}
This simple example can be run as is (several complex scenarios can be found in
the file \nsf{tcl/ex/simple-plm.tcl}).
\begin{program}
set packetSize 500 \;Packet size (in bytes);
set plm_debug_flag 2 \;Debugging output;
set rates "50e3 50e3 50e3 50e3 50e3" \;Rate of each layer;
set rates_cum [calc_cum $rates] \;Cumulated rate of the layers (mandatory);
set level [llength $rates] \;Number of layers (mandatory);
set Queue_sched_ FQ \;Scheduling of the queues;
set PP_burst_length 2 \;PP burst length (in packets);
set PP_estimation_length 3 \;Minimum number of PP required to make an estimate;
Class Scenario0 -superclass PLMTopology
Scenario0 instproc init args \{
eval $self next $args
$self instvar ns node
$self build_link 1 2 100ms 256Kb \;Build a link;
set addr(1) [$self place_source 1 3] \;Set a PLM source;
$self place_receiver 2 $addr(1) 5 1 \;Set a PLM receiver;
{\cf #set up the multicast routing}
DM set PruneTimeout 1000 \;A large PruneTimeout value is required;
set mproto DM
set mrthandle [$ns mrtproto $mproto \{\} ]
\}
set ns [new Simulator -multicast on] \;PLM needs multicast routing;
$ns multicast
$ns namtrace-all [open out.nam w] \;Nam output;
set scn [new Scenario0 $ns] \;Call of the scenario;
$ns at 20 "exit 0"
$ns run
\end{program}
Several variables are introduced in this example. They all need to be set in the
simulation script (there is no default value for these variables). In particular
the two following lines are mandatory and must not be omitted:
\begin{program}
set rates_cum [calc_cum $rates]
set level [llength $rates]
\end{program}
We describe now in detail each variable:
\begin{description}
\item[\tt packetSize] represents the size of the packets in bytes sent by the PLM
source.
\item [\tt plm\_debug\_flag] represents the verbose level of debugging output: from 0 no
output to 3 full output. For \code{plm_debug_flag} set to 3 (full output), long
lines output are
generated which is not compatible with nam visualization.
\item [\tt rates] is a list specifying
the bandwidth of each layer (this is not the cumulated bandwidth!).
\item [\tt rates\_cum] is a list specifying the cumulated bandwidth of the
layers: the first element of \code{rates_cum} is the bandwidth a layer 1, the
second element of \code{rates_cum} is the sum of the bandwidth of layer 1 and
layer 2, etc. The proc \proc{calc\_cum} computes the cumulated rates.
\item [\tt level] is the number of layers.
\item [\tt Queue\_sched\_] represents the scheduling of the queues. This is used by the
PLMTopology instproc \code{build_link}. PLM requires FQ scheduling or a
variation.
\item [\tt PP\_burst\_length] represents the size of the Packet Pair bursts
in packets.
\item [\tt PP\_estimation\_length] represents the minimum number of Packet
Pair required to compute an estimate (see
section~\ref{sec:PLMReception-Packet}).
\end{description}
All the simulations for PLM should be setup using the PLMTopology environment (as
in the example script where we define a PLMTopology superclass called Scenario0). The
user interface is (all the instproc can be found in \nsf{tcl/plm/plm-topo.tcl}):
\begin{description}
\item[\tt build\_link a b d bw] creates a duplex link between node
\code{a} and \code{b} with a delay \code{d} and a bandwidth \code{bw}. If
either node does not exist, \code{build_link} creates it.
\item[\tt place\_source n t] creates and places a PLM source at node \code{n} and
starts it at time \code{t}. \code{place_source} returns \code{addr} which
allows to attach receivers to this source.
\item[\tt place\_receiver n addr C nb] creates and places a PLM receiver at node
\code{n} and attached it to the source which return the address \code{addr}. The
check value for this PLM receiver is \code{C}. An optional parameter \code{nb}
allows to get an instance of the PLM receiver called \code{PLMrcvr($nb)}. This
instance is only useful to get some specific statistics about this receiver
(mainly the number of packets received or lost). %$
\end{description}
\section{The Packet Pair Source Generator}
This section describes the Packet Pair source generator; the relevant files are:
\nsf{plm/cbr-traffic-PP.cc}, \nsf{tcl/lib/ns-default.tcl}. The OTcl class name of
the PP source is: Application/Traffic/CBR\_PP.
The Packet Pair (PP) source generator is in the file
\nsf{plm/cbr-traffic-PP.cc}. This source
generator is a variation of the CBR source generator in \nsf{cbr\_traffic.cc}.
We just describe the salient differences between the code of
the CBR source and the code of the PP source.
The default values in \nsf{tcl/lib/ns-default.tcl} for the PP source generator are the same
than for the CBR source. We need for the PP source generator a new parameter {\tt PBM\_}:
\begin{program}
Application/Traffic/CBR_PP set PBM_ 2 \;Default value;
\end{program}
The OTcl instvar bounded variable {\tt PBM\_} (same name in C++ and in OTcl)
specifies the number of back-to-back packets to be sent. For {\tt PBM\_}=1 we
have a CBR source, for {\tt PBM\_}=2 we have a Packet Pair source (a source which
sends two packets back-to-back), etc. The mean rate of the PP source is
\code{rate_}, but the packets are sent in burst of \code{PBM_} packets. Note
that we also use the terminology Packet Pair source and Packet Pair burst for
{\tt PBM\_$>$2}.
We compute the \code{next_interval} as:
\begin{program}
double CBR_PP_Traffic::next_interval(int& size)
{
{\cf /*(PP_ - 1) is the number of packets in the current burst.*/}
if (PP_ >= (PBM_ - 1)){
interval_ = PBM_*(double)(size_ << 3)/(double)rate_;
PP_ = 0;
}
else {
interval_ = 1e-100; //zero
PP_ += 1 ;
}
...
}
\end{program}
The \proc{timeout} method puts the {\tt NEW\_BURST} flag in the first packet of a
burst. This is useful for the PLM protocol to identify the beginning of a PP
burst.
\begin{program}
void CBR_PP_Traffic::timeout()
{
...
if (PP_ == 0)
agent_->sendmsg(size_, "NEW_BURST");
else
agent_->sendmsg(size_);
...
}
\end{program}
\section{Architecture of the PLM Protocol}
The code of the PLM protocol is divided in three files: \nsf{tcl/plm/plm.tcl},
which contains the PLM protocol machinery without any specific interface with
\ns; \nsf{tcl/plm/plm-ns.tcl}, which contains the specific ns interface.
However, we do not guarantee the strict validity of this ns interfacing;
\nsf{tcl/plm/plm-topo.tcl}, which contains a user interface to build simulation
scenarios with PLM flows.
In the following we do not discuss the various procedures per object (for
instance all the instproc of the PLM class) but rather per functionality (for
instance which instproc among the various classes are involved in the instantiation
of a PLM receiver). For a given functionality, we do not describe in details all
the code involved, but we give the principal steps.
\subsection{Instantiation of a PLM Source}
To create a PLM source, place it at node \code{n}, and start it at {\tt t$_0$}, we call
the PLMTopology instproc {\tt place\_source n t$_0$}. This instproc return {\tt
addr}, the address required to attach a receiver to this source. {\tt
place\_source} calls the Simulator instproc \code{PLMbuild_source_set} that
creates as many
Application/Traffic/CBR\_PP instances as there are layers (in the following we call an
instance of the class Application/Traffic/CBR\_PP a layer). Each layer corresponds to a
different multicast group.
To speed up the simulations when the PLM sources start we use the
following trick:
At $t=0$, \code{PLMbuild_source_set} restricts each
layer to send
only one packet ({\tt maxpkts\_} set to 1). That allows to build the multicast trees
-- one multicast tree per layer -- without flooding the whole network. Indeed,
each layer only sends one packet to build the corresponding multicast tree.
The multicast trees take at most the maximum RTT of the network to be established and
must be established before {\tt t$_0$}, the PLM source starting time. Therefore,
{\tt t$_0$} must be carrefully chosen, otherwise the source sends a large number of
useless packets. However, as
we just need to start the PLM source after the multicast trees are estabished,
{\tt t$_0$} can be largely overestimated.
At time {\tt t$_0$}, we set {\it maxpkts\_} to 268435456 for all the layers.
It is fundamental, in order to have persistent multicast trees, that the
prune timeout is set to a large value. For instance, with DM routing:
\begin{program}
DM set PruneTimeout 1000
\end{program}
Each layer of a same PLM source has the same flow id {\tt fid\_}. Consequently,
each PLM source is considered as a single flow for a Fair Queueing
scheduler. The PLM code manages automatically the {\tt fid\_} to prevent different
sources to have the same {\tt fid\_}. The {\tt fid\_} starts at 1 for the first
source and is increased by one for each new source. Be careful to avoid other
flows (for instance concurrent TCP flows) to have the same {\tt fid\_} than the
PLM sources. Additionally, If you consider {\tt fid\_} larger than 32, do not
forget to increase the {\tt MAXFLOW} in \nsf{fq.cc} ({\tt MAXFLOW} must be set
to the highest {\tt fid\_} considered in the simulation).
\subsection{Instantiation of a PLM Receiver}
\begin{figure}[tbp]
\centerline{\includegraphics{instanPLMrecv.eps}}
\caption{Inheritance and instantiation when we create a receiver.}
\label{fig:instanPLMrecv}
\end{figure}
All the PLM machinery is implemented at the receiver. In this section we decribe
the instantiation process of a receiver. To create, place at node
{\tt n}, attach to source {\tt S}, and start at {\tt t$_1$} a PLM receiver we
call the PLMTopology instproc {\tt
build\_receiver n addr t$_1$ C} where {\tt addr} is the address returned
by {\tt place\_source} when {\tt S} was created, and {\tt C} is the check value. The
receiver created by {\tt build\_receiver} is an instance of the class PLM/ns,
the ns interface to the PLM
machinery. At the initialisation of the receiver, the PLM instproc {\tt init} is
called due to inheritance. {\tt init} calls the PLM/ns instproc
{\tt create-layer} and, by this way, creates as many instances of the class
PLMLayer/ns (the ns interface to the PLMLayer class) as there are layers. Each
instance of PLMLayer/ns creates an instance of the class PLMLossTrace which is
reponsible for
monitoring the received and lost packets thanks to the fact that the class
PLMLossTrace inherits from the class Agent/LossMonitor/PLM.
Fig.~\ref{fig:instanPLMrecv} schematically describes the process of a PLM
receiver instantiation. In the following we describe the behavior of a PLM
receiver when it receives a packet and when it detects a loss.
\subsection{Reception of a Packet}
\label{sec:PLMReception-Packet}
We create a new c++ class PLMLossMonitor (\nsf{plm/loss-monitor-plm.cc}) that
inherits from LossMonitor. The OTcl class name of the c++ PLMLossMonitor class is
Agent/LossMonitor/PLM.
\begin{program}
class PLMLossMonitor : public LossMonitor {
public:
PLMLossMonitor();
virtual void recv(Packet* pkt, Handler*);
protected:
// PLM only
int flag_PP_;
double packet_time_PP_;
int fid_PP_;
};
static class PLMLossMonitorClass : public TclClass {
public:
PLMLossMonitorClass() : TclClass("Agent/LossMonitor/PLM") {}
TclObject* create(int, const char*const*) {
return (new PLMLossMonitor());
}
} class_loss_mon_plm;
\end{program}
We add in {\tt void PLMLossMonitor::recv(Packet* pkt, Handler*)} a Tcl call to the
Agent/LossMonitor/PLM instproc {\tt log-PP} each time a packet is received :
\begin{program}
void LossMonitor::recv(Packet* pkt, Handler*)
{
...
if (expected_ >= 0) {
...
}
Tcl::instance().evalf("%s log-PP", name());
}
\end{program}
The Agent/LossMonitor/PLM instproc {\tt log-PP} is empty. In fact, we define the {\tt
log-PP} instproc for the class PLMLossTrace. {\tt log-PP}
computes an estimate of the available bandwidth based on a single PP burst (of
length {\tt PP\_burst\_length} in packets). Once {\tt log-PP} has received the
{\tt PP\_burst\_length} packets of the burst, it computes the estimate and
calls the PLM instproc {\tt make\_estimate} with the computed estimate as
argument.
{\tt make\_estimate} puts the estimate based on a single PP
({\tt PP\_value}) in an array of estimate samples ({\tt PP\_estimate}). If {\tt
PP\_value} is lower than the current subscription level (i.e.~lower than the
throughput achieved according to the current number of layers subscribed), {\tt
make\_estimate} calls the PLM instproc {\tt stability-drop} which simply drops
layers until the current subscription level becomes lower than {\tt PP\_value}.
{\tt make\_estimate} makes an estimate {\tt PP\_estimate\_value} by taking the
minimum {\tt PP\_value} received during the last {\tt check\_estimate} period
(if there are at
least {\tt PP\_estimation\_length} single PP estimate received). Once {\tt
make\_estimate} has a {\tt PP\_estimate\_value} it calls the PLM instproc {\tt
choose\_layer} which joins or drops layer(s) according to the current subscription
level and to the {\tt PP\_estimate\_value}. For details about the PLM instproc
\code{make_estimate}, refer to its code in \nsf{tcl/plm/plm.tcl}.
\subsection{Detection of a Loss}
Each time a loss is detected by an instance of the class PLMLossMonitor, a call to
the Agent/LossMonitor/PLM instproc {\tt log-loss} is triggered. The
Agent/LossMonitor/PLM instproc {\tt log-loss}
is empty. In fact, we define the {\tt log-loss} instproc for the class
PLMLossTrace. The PLMLossTrace instproc {\tt log-loss} simply
calls the PLM instproc {\tt log-loss} which contains the PLM machinery in case
of loss. In summary, {\tt log-loss} only drops a layer when the loss rate
exceeds 10\% (this test is executed by the PLM instproc {\tt
exeed\_loss\_thresh}). After a layer drop {\tt log-loss} precludes any
other layer drop due to loss for 500ms. For details about the PLM instproc {\tt
log-loss}, refer to its code in \nsf{tcl/plm/plm.tcl}.
\subsection{Joining or Leaving a Layer}
To join a layer the PLM instproc {\tt add-layer} is called. This instproc
calls the PLMLayer instproc {\tt join-group} which calls the PLMLayer/ns instproc {\tt
join-group}.
To leave a layer the PLM instproc {\tt drop-layer} is called. This instproc
calls the PLMLayer instproc {\tt leave-group} which calls the PLMLayer/ns instproc {\tt
leave-group}.
\section{Commands at a Glance}
Note: This section is a copy paste of the end of
section~\ref{sec:Configuration}. We add this section to preserve homogeneity with
the ns manual.
All the simulations for PLM should be set using the PLMTopology environment (as
in the example script where we define a PLMTopology superclass called Scenario0). The
user interface is (all the instproc can be found in \nsf{tcl/plm/plm-topo.tcl}):
\begin{description}
\item[\tt build\_link a b d bw] creates a duplex link between node
\code{a} and \code{b} with a delay \code{d} and a bandwidth \code{bw}. If
either node does not exist, \code{build_link} creates it.
\item[\tt place\_source n t] creates and places a PLM source at node \code{n} and
starts it at time \code{t}. \code{place_source} returns \code{addr} which
allows to attach receivers to this source.
\item[\tt place\_receiver n addr C nb] creates and places a PLM receiver at node
\code{n} and attached it to the source which return the address \code{addr}. The
check value for this PLM receiver is \code{C}. An optional parameter \code{nb}
allows to get an instance of the PLM receiver called \code{PLMrcvr($nb)}. This
instance is only useful to get some specific statistics about this receiver
(mainly the number of packets received or lost). %$
\end{description}
}
|