Basic network example
Description
This basic network example models an end-to-end TCP connection between two endpoints, one standing as
sender and the other one as
receiver (i.e., the channel is not full-duplex). Data packets pass through a
router, which routes them following a flow-based approach.
Model creation
- Open PowerDEVS and select
File --> New
to create a new model.
- Add the following atomic models by dragging and dropping them from library
Data Networks (High-Level)
:
-
TcpSender
: a coupled DEVS model that acts as a TCP endpoint, managing the data and congestion windows and the usual TCP internals. Double-click on its name and change it to Sender.
-
TcpReceiver_5sessions
: a coupled DEVS model that acts as a passive TCP endpoint, acknowledging data received (it is called 5 sessions
since it offers the possibility of using up to five connections simultaneously). Change its name to Receiver.
-
Router
: a coupled DEVS model that represents a network router. Change its name to Router.
- Now we should perform the appropriate connections between the models so that the data flows as expected. In order to do this,
- Left-click and hold the Sender 's output arrow (on its right side) and release it over the top left input arrow of the Router.
- Do the same for the Router 's top output arrow and the Receiver 's input arrow.
- Finally, connect the Receiver 's output with the Sender 's input.
- After this, you should have a model similar to the one shown below:
</verbatim>
- The next step is configuring the model parameters. For this we will use the input file
network_basic.params
located in examples/network/basic
, but first we should tell PowerDEVS how to map the values read to the actual model parameters.
- First, double-click on Sender and complete each
Parameter
like so:
-
bandwidth
: fastLink
(string values like this are parsed from the input file)
-
propagation
: 0.001
(numerical values are used directly)
-
flowName
: Sender
-
ipSender
: Sender
-
ipReceiver
: Receiver
-
portReceiver
: 0
-
TCP.MSS
: MSS
-
TCP.CWND_max
: 250
-
TCP.CWND_ssthresh
: 64
-
TCP.RTT_initial
: 0.2
- Use the following for Router:
-
bufferSize
: queueSize
-
bandwidth
: slowLink
-
propagation
: 0.001
- And the following for Receiver:
-
TCP.MSS
: MSS
-
bandwidth
: slowLink
-
propagation
: 0.001
-
ipSender
: Sender
-
ipReceiver
: Receiver
Execution
- We are now ready to compile the model into a standalone executable and run our simulations. Fortunately, PowerDEVS does this automatically for us: just left-click on the
Simulate
button located in the top toolbar (the white triangle resembling a 'play' arrow). After some seconds, the simulation window should appear. You can safely close it as we are going to run our simulations from a terminal.
- Thus, open a terminal and go to the
output
directory inside PowerDEVS root directory. Assuming it was installed in /home/user/powerdevs
, you should execute the following command:
-
$ cd /home/user/powerdevs/output
- If you list the files there, you should see an executable file called
model
. This is indeed the file that PowerDEVS compiled for us before.
- Before running the simulation, we should assemble a very simple finalization script in Python that will be called automatically by PowerDEVS after everything is done. In our case, we will instruct the simulation engine to execute a Scilab script to plot some values logged by our models. So, edit a file called
finalization.py
and add there the following lines:
import py2pdevs.core as core
import os
core.run_scilab_script('%s/../examples/network/basic/network_basic.sce' % os.getcwd())
- Now run a simulation parametrized as follows:
-
$ ./model -tf 30 --c ../examples/network/basic/network_basic.params --finalization_script ../examples/network/basic/finalization.py
- This basically tells PowerDEVS that it should simulate the model for 30 seconds using the parameters listed in the input file
../examples/network/basic/network_basic.params
and using our previously created script to perform finalization tasks (which will just be creating a couple of plots).
- After some seconds the simulation should end and a plot like the following should be produced:
</verbatim>
- Congratulations! You've just finished your first basic example. You can find the complete source importing in PowerDEVS the file
network/basic/network_basic.pdm
.
Developer notes
- When PowerDEVS compiles the model into a standalone executable, it actually generates first a C++ header file providing an instanciation of the class
Model
with the appropriate behavior of the model assembled by the user. This header can be found in build/model.h
.
- The autogenerated constructor of the class takes an initial time and contains code that instanciate and connect the models as requested by the user.
- In case you should need to manually modify something in the code, you can recompile by issuing
make
inside the build
directory. This will regenerate the model
executable inside the output
directory.
Model creation in py2pdevs
Advanced users interested in running this model in
py2pdevs have to code a Python script to assemble the model structure and setting up parameter initialization and finalization tasks. We will see in detail how to do this. First, go to the
build/lib
directory and edit a new Python file named
network_basic.py
. Paste the following code. Next we will briefly explain what is going on here:
import os
import sys
# Make py2pdevs package visible. An alternative is to export the environment variable PYTHONPATH appeding the absolute path to
# build/lib and then running the script without the following line.
sys.path.append('../../../../build/lib')
import py2pdevs.core as core
import py2pdevs.network as network
import py2pdevs.library.datanetworks_ext as library
from py2pdevs.network.distributions import Normal
def network_basic():
fast_link = 10000000
slow_link = 5000000
# create top model. Set some global parameters
global_params = {"TCP.CWND_max":250, 'TCP.CWND_ssthresh': 64, 'TCP.RTT_initial': 0.2, "MSS":1024}
model = network.new_model('network_basic',
params = global_params, # parameters as dictionary
bufferSize=500000, # parameters as keywords
propagationDelay=0.001)
# Create network objects. Parameters to individual models
receiver = library.TcpReceiverExt(model, 'Receiver', bandwidth=slow_link)
router = library.RouterExt(model, 'Router', bandwidth=slow_link)
sender =library.TcpSenderExt(model, 'Sender', bandwidth=fast_link, set_samplers = False)
# Models can be connected in the following way.
# For network models, it is not necesary as it is done automatically by defining flows as below
# model.connect((router, 0), (receiver, 0))
# Define the flow for the sender model (a flow is the path that packets will take along the network, and the size of the packets. Optionally there could be other attributes as QoS for example).
# Models are by default automatically connected with in duplex link. The default return path is equal to the send path reverted
flow = model.new_flow("Sender_flow", src=sender, dst=receiver, packet_size=Normal(3624, 800))
flow.set_route((sender, 0, 0), (router, 1, 0), (receiver, 0, 0)) # route is in the form : (node1, inport, outport), ...
# Configure logging
# this is yet another way of setting parameters (this could also be donde in a configuration file, when instanciating each model, or globaly when creating the top model)
params = model.get_global_parameters()
params['TCP_SND.logLevel'] = 1000 # log CWND
params['queue.logLevel'] = 1000
model.set_global_parameters(**params)
# Run model and finalize.
model.run()
finalize()
def finalize():
core.run_scilab_script('%s/../network_basic.sce' % os.getcwd())
if __name__ == '__main__':
network_basic()
As you can see, the main function is
network_basic()
, which does the following:
- It declares a new root model named
network_basic
. It is stored in the variable model
. Note that several parameters are passed as key-value arguments. Later, when network DEVS models are created, these parmeters will be used as default parameters if none are supplied.
- Then, the main components of the model are created: the TCP receiver, the router and the TCP sender.
- After this, they are connected as in the picture shown above.
- Next, the data flow to connect the sender and the receiver is defined. It can be configured with a probability distribution for the packet size (in this case, the sizes follow a normal distribution with mean 3624 and standard deviation 800) and another one for the interpacket period. If not supplied, it defaults to uniform distribution.
- Then, logging is configured by registering the log variables in which the user is interested. In this case, we instruct PowerDEVS to log the congestion window (CWND) of the sender associated to the aforementioned flow, and the router queue size associated to interface 0.
- Finally, the simulation is run and a finalization function to plot the results is called.
Running the script
We are all set! To run the script, execute the following command in a terminal (make sure you are inside the
build/lib
directory):
-
python network_basic.py -tf 30
Notice that, as opposed to running the model created through the graphical interface, we don't need to specify the parameter file nor the finalization script. The former is replaced by global parameters supplied to the model object and interactions between other Python objects (e.g. flows and log variables) whereas the latter is replaced by another function inside the main script (
finalize()
).
After a while, the simulation should end and the same plot depicted in the previous section should pop up.
Complete model
For reference, you can find the complete model script in
examples/network/basic/py2pdevs/network_basic.py
.
Exercise
- Try modifying the parameters of the Sender and interpreting the plots obtained in each situation.