The primary objective of this assignment is to gain a deeper understanding of the TCP congestion control algorithm. In addition, this assignment will help you to familiarize yourself with the ns3 network simulator and to understand the process of conducting experiments, collecting data, and analyzing data.
The ns3 simulator
For this assignment, we will be using the ns3 network simulator. This is the most commonly used software in the Internet research community, and because of this popularity there are many protocols written for it. Most TCP research uses ns, so it has a large set of TCP variants.
ns3 is an event-driven, packet-level simulator. This means that the simulator steps through a series of events using a simulated notion of time, and it simulates each packet in a connection.
Please see the ns3 tutorial for help with installing and learning to use ns3. You may also find the ns3 documentation handy. You should look at the classes under the Class List to see the documentation for each class if you have any detailed questions.
To run ns3, you create a C++ script to create a network topology and generate workload. ns3 will simulate each part of the network down to the network device cards and the channels they communicate on; so each of these components must be setup. Fortunately there are a number of helpers that do most of the dirty work for you.
Scripts usually start out by defining the nodes (machines) in the network. A Node Container is a data structure that will both hold and create nodes.
NodeContainer c; c.Create(2);
In order to connect the nodes in the network we will use a the PointToPointHelper. This helper creates a link between two and only two nodes. It is then used to install the NIC (Network Interface Controller) on the two nodes, linking them together.
PointToPointHelper pointToPoint; pointToPoint.SetDeviceAttribute("DataRate",DataRateValue(DataRate("1.5Mbps"))); pointToPoint.SetChannelAttribute("Delay", TimeValue(Time("10ms"))); NetDeviceContainer devices; devices = pointToPoint.Install(nodes);
We then install the Internet stack that creates the protocols and layers necessary for sending packets across the link.
Now we assign addresses to the nodes. The Ipv4AddressHelper does all the work for us. We only need to assign network base and the netmask. These addresses are assigned to the NIC devices that were created by the PointToPointHelper.
Ipv4AddressHelper address; address.SetBase("10.1.1.0", "255.255.255.0"); Ipv4InterfaceContainer interfaces = address.Assign (devices);
Now we must create applications on the nodes that will make use of the link we just set up. The sink is setup using the PacketSinkHelper. We need only specify the type of socket factory and the address the application will be listening on. In this case we will listen on "0.0.0.0", port 8080 so the application will listen on all available interfaces. We also specify when the application will both start and stop in the simulation.
int16_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(50.));
Next, we create the source application. We will use what is called an OnOffApplication and will create it with and OnOffHelper. An OnOffApplication can be setup to cycle through on and off states, but we will set it up to simply be on for the entire life of the simulation. In the lab3-single-flow script a custom application is used in order to setup a trace on the congestion window, so don't be confused when you see something different going on there. The OnOffHelper requires you to specifiy the type of socket factory and remote address. Other attributes that are set are the OnTime and OffTime (which was previously discussed), the DataRate, and the PacketSize. These should be self explanatory. We then install the application on a given node and specify the start and stop time for the application.
OnOffHelper server("ns3::TcpSocketFactory",InetSocketAddress(interfaces.GetAddress(1), port + i)); server.SetAttribute("OnTime", RandomVariableValue(ConstantVariable(50))); server.SetAttribute("OffTime", RandomVariableValue(ConstantVariable(0))); server.SetAttribute("DataRate", DataRateValue(DataRate("1.5Mbps"))); server.SetAttribute("PacketSize", UintegerValue(2000)); serverApp[i] = server.Install(nodes.Get(0));
If the packets must travel through intermediate nodes to reach their destination, we must also setup routing. This is very easy to do in ns3 if you simply want static routes.
You probably noticed the beginning of most of the files have of the format Config:SetDefault("ns3::..."). These statements are an easy way to setup default values for attributes deep in the simulator, where otherwise it would be a pain to create the object and go through all the accessor methods to change the default setup of the simulator. For example, the statement:
Config::SetDefault("ns3::TcpL4Protocol::SocketType",TypeIdValue(TypeId::LookupByName("ns3::TcpTahoe")));changes the default socket type for the TcpL4Protocol from the default value of ns3::TcpNewReno to ns3::TcpTahoe. The Tcpl4Protocol is used in the InternetStack and in the TcpSocketFactory to generate the type of tcp socket that will be used. So in one command, without digging into the SocketFactory or Internet Stack we can change all the values.
With all these settings up and ready to go we could run the simulator now and everything would run, but we also want to get information out of the simulator, as to what happened. Perhaps the most well known way is to create a trace file. This is done with the PointToPointHelper using the following commands:
AsciiTraceHelper ascii; pointToPoint.EnableAsciiAll(ascii.CreateFileStream("lab3-nflow.tr"));
The standard ns3 trace file does not include TCP's congestion window over time. To obtain this value, the lab3-single-flow.cc uses a callback method called CwndTracer().
ns3 provides a convenient way to create callbacks on specific events. For example in the provided scripts, every time a packet in enqueued to be sent out, the Enqueue method is called. These hooks are setup for Enqueue, Dequeue, Dropped Packets, and received packets. They allow you to potentially do all your computation in the script without having to parse a trace file and you don't have to recompile anything to add and use them.
It should also be mentioned that the logging done in the callback methods will not show up unless you uncomment the following line near the beginning of the main method in each of the scripts.
All logging messages are output to the standared error. If you want something to be output to standard output use
std::cout << "This will go to the standard out" << std::endl
since the scripts are in the ns3 namespace.
ns3 also has implemented Gnuplot and GnuplotDataset classes that will store your data and output it in gnuplot friendly format. If you are interested in this, look at examples/wireless/wifi-adhoc.cc to get better idea of how gnuplot can be used.
The following shows the format of the ns3 packet trace:
- Event: '+': a packet was enqueued, '-': a packet was dequeued, 'd': a packet was dropped, or 'r': a packet was received at the end of a link
- Time: The time at which the event occurred
- From: The starting node for the link on which the event occurred
- To: The ending node for the link on which the event ocurred
- Type: The packet type, for example 'tcp'
- Size: The size of the packet in bytes
- Flags: You can ignore this field
- Class: The 'class' of the packet, which can be used to identify a particular TCP connection
- Source: The source address of the packet, given as "node.port"
- Dest: The destination address of the packet
- Sequence: The sequence number of the packet
- Identifier: The unique identifier of the packet
Part 1: Single Flow TCP Experiment
Use the single-flow.cc script to run an experiment with a single TCP connection over a network of two nodes. The topology for this script looks like this:
Using the generated trace files, produce graphs for the following:
- The receiver's rate over time. To plot a smooth rate, calculate the rate over a moving window of 10 packets. You can do this by plotting a point every time a packet is received: if packeti is received at time ti, plot a point at ti equal to the sum of the lengths of packeti-10 through packeti, divided by the ti - ti-10. You will need to modify this slightly to handle the start of the connection, when there are fewer than 10 previous packets.
- The queue size over time and each packet drop event. You can calculate the queue size at any time by observing all packet enqueue, dequeue, and drop events. Plot each drop event at the maximum queue size (10) when the drop occurs using an "X" symbol.
- The congestion window over time.
Note that for all of these graphs you will need to exclude ACK packets, which are listed in the trace file along with TCP data packets.
Repeat this experiment for TCP Tahoe and NewReno. Turn in all of your graphs and the answers to the following questions (each worth 10 points):
- Examining the results for TCP NewReno, why is TCP able to have a sawtooth pattern for the congestion window, but a relatively smooth rate as observed at the receiver?
- What differences do you observe between Tahoe and NewReno, and why do these differences occur?
Part 2: Multiple Flow TCP Experiment
Use the nflow.cc script to run an experiment with multiple TCP connections over the same network of two nodes. The topology for this script looks like this:
Connection 1 starts at time 0, Connection 2 at time 5, Connection 3 at time 10, Connection 4 at time 15, and Connection 5 at time 20. End Connection 1 at time 50.1, Connection 2 at time 45, Connection 3 at time 40, Connection 4 at time 35, and Connection 5 at time 30. The script includes the following line when creating each TCP connection:
$tcp set class_ $i
where $i is the number of the connection. This uses the class (0 - 4) to distinguish the five TCP connections in the packet trace.
Using the generated trace files, produce graphs for the following:
- The receivers' rates over time. Calculate the rate for each TCP connection separately, using the same methodology as the first part. Plot the rate for all of the receivers on the same graph.
- The queue size over time and each packet drop event. This should be the same type of graph as in the first part.
Use only TCP NewReno for this experiment. Turn in all of your graphs and the answers to the following questions (each worth 10 points):
- What do you observe about fairness among the various TCP connections?
- What do you observe about the queue size and packet drops?
Part 3: Varying the RTT
Use the rtt.cc script to setup this topology:
The queue size limit on all nodes is 10. The bandwidth on Links 1 and 2 is 1.5 Mbps. The propagation delay on Links 1 and 2 is initially 10 ms, but you will be varying the propagation delay on Link 2 for your experiments.
Connection 1 starts at time 0, using Link 1. Connection 2 starts at time 0. Both connections run for 5 seconds.
Graph the throughput for each connection over time and observe that they get approximately the same amount. Now run a set of experiments, varying the propagation delay on Link 2 so that Connection 2 has an increasingly longer RTT. Produce the following graph:
- The receiver's total rate (averaged over the length of the connection) versus the propagation delay on Link 2. Plot each connection separately.
Use only TCP NewReno for these experiments. Turn in your graph and the answers to the following question (worth 10 points):
- What do you observe about the relationship between RTT and fairness in TCP?
Turn in a typed report that includes all of your graphs and your answer to each of the questions. Each answer should be about a paragraph long. You will be graded based on how well you explain your answers to the grader so that we can tell you understand the simulation results.
Turn in a PDF of your report. Email the report to byucs460 [at] gmail.com . The date on your email is the timestamp for your lab and determines whether you turned it in on time.
Your report will be graded on a scale of 10 points per question, the same as the homework assignments, for a total of 50 points.