This assumes that your platform has
Python with
matplotlib.
(Easily installed via a distribution
like
Anaconda
(cross-platform) or
WinPython
(Windows).)
the tssnet library for your platform (e.g., tssnetlib_win32bit_0.dll)
the tssnet Python module (tssnet_0.py)
To simulate a network,
you write a script that uses tssnet_0.py
to construct the network, simulate it, and log and plot metrics.
Example scripts are here.
To run any of them,
say net-1.py,
download the script and execute it
in a directory containing the library and Python module.
You should see plots as shown
here.
(Note: not tested within an IDE.)
Scripts
In general,
a script imports tssnet_0.py (which imports the tssnet library)
and then uses the functions provided by tssnet_0.py
to construct a network, simulate it, and log and plot metrics.
The
tssnet library has a C interface
(so it can be used by any program that can link to a C library).
Its functions are grouped into the following:
Network update:
update a network's state by one timestep.
Metric gettors:
return the current values of a network's metrics.
The Python module, tssnet_0.py, has three classes:
Network:
wrapper for the tssnet library.
NetworkLogPlot:
log a network's metrics, plot metrics (using matplotlib).
NetworkPlotDynamic:
dynamically plot a network's metrics (using matplotlib).
The typical structure of a script is as follows:
import tssnet_0.py
// create a network n
create an empty network n
add nodes to n
add links to n
set the default routes in n
add tcp flows to n
add udp flows to n
// simulate network n
set random seed for n
while "not done":
update n by one timestep
log the time and metrics of n
// plot metrics of n
plot logged metrics vs logged time
In the simulate stage,
the "not done" condition
can depend on the time and metrics of network n.
For example:
(time < 20 seconds) and
(flow j's received data < 50000 bytes).
The calls to tssnet need not be in the above order.
The stages can be interleaved.
For example,
immediately after a flow ends,
one can start a new flow and continue simulating.
The parameters and endpoints of the new flow
can depend on the metrics achieved by the old flow.
One can also create multiple networks,
and then simulate them in lock-step
(updating all networks in each timestep),
for example, to stop the simulation as soon as
two similar networks diverge in their behavior.
Network model
Conceptually, the nodes and links model the IP layer.
There can be at most one link from one node to another.
Links are unidirectional,
so two links are needed for a bidirectional link between two nodes.
The tcp and udp flows model the application layer.
Each flow has a source at one node that sends
a given amount of data to a sink at another node,
starting at a given time and using the relevant protocol (tcp or udp).
There can be multiple tcp and udp flows from one node to another,
and the flows can use different data and ack paths.
Limitations in tssnet_0:
The propagation delay of a link has to be at least 0.03 seconds (30 ms).
Application data is in 1000-byte multiples.
Tcp packets have 1000-byte data and 24-byte header.
Udp packets have 1000-byte data and 24-byte header.
Tcp's initial 3-way handshake is not modeled.
(But the effect on completion time can be captured quite well
simply by increasing the data load by 1000 bytes;
e.g., instead of 100000 bytes, send 101000 bytes.)
Details of tssnet library
Creating a new network
create_network()
creates an empty network and returns a pointer to it.
Nodes
add_node(n, nid)
adds a node with integer id nid
to network n.
Links
A link goes from one node (source) to another node (destination).
There can be at most one link from one node to another.
Conceptually,
a link consists of a buffer and transmitter in the source node,
and a wire from the source node to destination node.
The buffer holds packets awaiting transmission.
The wire holds packets in flight.
The transmitter moves packets from buffer to wire.
add_link(n, srcnid, dstnid, rate, cvsq, buffersize, propdelay, cost)
adds to network n a link with the following attributes:
srcnid: source node id.
dstnid: destination node id.
rate:
rate (bytes/second) at which packets are sent
from the buffer to the wire (i.e., link bandwidth).
cvsq,
coefficient of variation squared of the transmit rate.
This introduces statistical variation essential for realistic simulation.
A small nonzero value suffices, e.g., 0.05.
buffersize:
maximum number of bytes the buffer can hold.
propdelay:
propagation delay (seconds),
i.e., time taken by a packet to cross the wire.
cost: cost of the link for purposes of shortest-path routing.
Default routes
set_default_routes(n)
sets the routing tables at nodes so that every node has a
shortest-path route to every (reachable) destination.
The cost of a route is the sum of the costs of the links of the route.
When a (tcp or udp) flow is added to the network,
its data path (and ack path, if tcp) is set either
to the default route or to an explictly-stated route.
In either case, the flow's path does not change later
(even if the default route subsequently changes
due to adding new links).
Tcp flows
A tcp flow has a source at one node that sends a given amount of data
to a sink at another node, starting at a given time
and using the tcp protocol.
The sink acks immediately and has unlimited receive window.
The flow's "data path" (taken by the data packets)
can be either the default route or explicitly specified.
The same applies to the "ack path" (taken by ack packets).
add_tcp(n, srctype, srcnid, snknid, starttime, datasize)
adds to network n a tcp flow
that uses the default routes for its data and ack paths:
srctype: the type of tcp source: Tahoe, Reno, or NewReno.
srcnid: id of the node where the tcp source is located.
snknid: id of the node where the tcp sink is located.
starttime (seconds): time when the source starts sending.
datasize (bytes): the amount of data to send.
The function returns a positive integer that is the id of the tcp flow;
no other flow (tcp or udp) in network n has that id.
The return value is also the id of the flow's source.
The return value + 1 is the id of the flow's sink.
add_tcp_with_route(n, srctype, datapath, datapathlen,
ackpath, ackpathlen, starttime, datasize)
adds a tcp flow with explictly-stated data and ack paths.
The parameters and return value are as in add_tcp()
except that the following parameters replace
srcnid and snknid:
datapath: array of node ids defining the data path
(starting with the source node id and ending with the sink node id).
datapathlen: length of datapath (≥ 2)
ackpath: array of node ids defining the ack path
(starting with the sink node id and ending with the source node id).
ackpathlen: length of ackpath (≥ 2)
Udp flows
A udp flow has a source at one node that sends a given amount of data
at a fixed rate to a sink at another node, starting at a given time.
The sink does not send acks.
The flow's "data path" (taken by the data packets)
can be either the default route or explicitly specified.
add_udp(n, srcnid, snknid, srcrate, starttime, datasize)
adds to network n a udp flow
that uses the default route for its data path:
srcnid: id of the node where the udp source is located.
snknid: id of the node where the udp sink is located.
srcrate: rate (bytes/second) at which the soure sends.
starttime (seconds): time when the source starts sending.
datasize (bytes): the amount of data to send.
The function returns a positive integer that is the id of the udp flow;
no other flow (tcp or udp) in network n has that id.
The return value is also the id of the flow's source.
The return value + 1 is the id of the flow's sink.
add_udp_with_route(n, datapath, datapathlen, srcrate,
starttime, datasize)
adds a udp flow with explictly-stated data paths.
The parameters and return value are as in add_tcp()
except that the following parameters replace
srcnid and snknid:
datapath: array of node ids defining the data path
(starting with the source node id and ending with the sink node id).
datapathlen: length of datapath (≥ 2)
Simulation
set_randomseed(n, seed) initializes the random number
generator with seed.
Use different seeds to see random variations in the metrics generated
for the same network.
Over tens of timesteps, the variation may be minor,
but over hundreds of timesteps, they can be significant
(see here).
update_network(n) updates the state of network n
by one timestep and returns the updated simulation time.
Thus the simulation time takes the values
t0,
t1,
t2,
…,
where
[t0, t1],
[t1, t2],
…
are the timesteps.
Link metrics
Below are for a link with id j in network n.
get_inbuffsize(n, j)
returns the number of bytes currently in the buffer of the link.
get_arrivedsize(n, j),
when called at the end of a timestep,
returns the number of bytes that arrived at the link in that timestep.
get_droppedsize(n, j),
when called at the end of a timestep,
returns the number of bytes that were dropped (due to buffer overflow)
at the link in that timestep.
Tcp metrics
Below are for a tcp flow with id j in network n.
Recall that its source has id j
and its sink has id j+1.
get_sentsn(n, j)
returns the current value of sentsn,
defined as
the highest data sequence number + 1 ever sent by the source.
get_ackdsn(n, j)
returns the current value of ackdsn,
the highest ack sequence number ever received by the source.
get_cwsize(n, j)
returns the current value of cwsize,
defined as
the size (bytes) of the congestion window (at source).
get_sentsize(n, j)
returns the current value of sentsize,
defined as
the total number of data bytes sent by the source (since the start).
get_rcvdsn(n, j+1)
returns the current value of rcvdsn,
defined as
the data sequence number expected by the sink
(i.e., the number of bytes of data delivered to the sink's local user).
get_rcvdsize(n, j+1)
returns the current value of rcvdsize,
defined as
the total number of data bytes received by the sink (since the start).
Udp metrics
Below are for a udp flow with id j in network n.
Recall that its source has id j
and its sink has id j+1.
get_sentsn(n, j)
returns the current value of sentsn,
defined as
the highest data sequence number + 1 ever sent by the source.
(Same as for tcp.)
get_sentsize(n, j)
returns the current value of sentsize,
defined as
the number of data bytes sent by the source since the start.
(Same as for tcp.)
Because this source does not retransmit or skip data,
its sentsize and sentsn are always equal.
get_rcvdsn(n, j+1)
returns the current value of rcvdsn,
defined as the highest data sequence number
ever received by the sink.
(Differs from tcp.)
get_rcvdsize(n, j+1)
returns the current value of rcvdsize,
defined as
the total number of data bytes received by the sink.
(Same as for tcp.)
Details of tssnet Python module
tssnet_0.py has classes
Network, NetworkLogPlot,
and NetworkPlotDynamic.
Class Network()
This is a wrapper for the tssnet library.
Network()'s constructor wraps tssnet's create_network().
So "n = Network()" corresponds to "n = create_network()".
A method f(.) of Network()
wraps tssnet's function f(n, .).
For example, "n.add_node(j)" corresponds to "add_node(n, j)".
There is a bit of garnish.
In method add_link,
parameter cost defaults to 1
(resuling in default routes being min-hop paths).
In method add_tcp,
parameter srctype is now a string and it defaults to 'NewReno'.
In method add_tcp_with_route,
parameter datapath is now a Python list
and datapathlen is eliminated.
And so on.
Class NetworkLogPlot()
This handles logging of metrics,
generating plots of logged metrics (using matplotlib),
dumping logs to file and restoring them (using pickle).
Logging
nlp = NetworkLogPlot(n),
where n is a network,
creates an instance for logging metrics of the network.
nlp.log_link(j, nm)
tags link j of the network as a link to be logged
under (string) name nm.
(The name is used to identify the link in plots.)
Analogously, nlp.log_tcp(j, nm)
tags tcp flow j of the network for logging,
and
nlp.log_udp(j, nm)
tags udp flow j of the network for logging.
nlp.update_logs(t)
reads the metrics of of all network components tagged for logging,
and adds them to the log under time t.
So t should be the current time,
i.e., returned by the last call of " n.update_network()".
Plotting
nlp.plot_linklog(nm)
displays one figure of one plot of logs of the link named nm,
(i.e., a plot of [inbuffsize, arrivedsize, droppedsize] vs time).
Does nothing if nm is not the name of a tagged link.
nlp.plot_linklogs(m, names),
where m is a positive integer
and names is a list of names of tagged links,
generates one plot for each name in names,
grouped into m plots per figure.
So it generates a total of len(names)/m figures.
Ignores entries in names that are not names of tagged links.
nlp.altplot_linklogs(names),
where names is a list of names of tagged links,
generates one figure with three plots:
inbuffsize vs time, for all names in names;
arrivedsize vs time, for all names in names;
and
droppedsize vs time, for all names in names.
Ignores entries in names that are not names of tagged links.
nlp.plot_tcplog(nm),
nlp.plot_tcplogs(m, names),
and nlp.altplot_tcplogs(names)
are the analogous methods for tcp flows.
nlp.plot_udplog(nm),
nlp.plot_udplogs(m, names),
and nlp.altplot_udplogs(names)
are the analogous methods for udp flows.
Pickling
nlp.pickle_logs(pathname) dumps all the logs into
file pathname.
nlp.pickle_logs(pathname) loads file pathname
into the logs of nlp.
Typically, you would not use nlp but a fresh instance,
say x, created by
x = NetworkLogPlot(None).
Class NetworkPlotDynamic()
This generates dynamic plots of a network simulation,
i.e., without storing the metrics into a log
(using matplotlib.Animation).