The first session builds the smallest possible network in NS-3, two nodes on a point-to-point link, and runs a UDP client and server over it. Every later topology is this pattern repeated.
Objectives
Do not copy. Read for understanding and the viva- Complete questions 1 to 2 of the manual: point-to-point topology and udp echo
- Prepare the deliverable before the lab and finish it during the session
- Be ready to explain every step in the viva
Questions Covered
Do not copy. Read for understanding and the viva| Question | Requirement | Status |
|---|---|---|
| Q1 | Create a simple point to point network topology using two nodes | Complete |
| Q2 | Create a UdpClient and UdpServer nodes and communicate at a fixed data rate | Complete |
Preparation
Do not copy. Read for understanding and the viva- Read
first.ccin the NS-3 tutorial; it is the answer to question 1 with different parameters. - Know the helper sequence: NodeContainer, PointToPointHelper (DataRate, Delay), InternetStackHelper, Ipv4AddressHelper, UdpEchoServerHelper and UdpEchoClientHelper.
- Fixed data rate for the client means setting MaxPackets, Interval and PacketSize attributes; compute the rate with the CBR formula below.
Question 1
Problem Statement
Write in lab recordCreate a simple point to point network topology using two nodes.
Solution
Write in lab recordSteps
- Install ns-3 (3.36 or later) and build it once:
./ns3 configure --enable-examples && ./ns3 build. - Save the program below as
scratch/p2p_two_nodes.cc. Anything inscratch/is compiled automatically. - Run
./ns3 run scratch/p2p_two_nodes. The first run compiles the file; later runs start at once. - Draw the topology in the record: two boxes, one line, the link parameters and the two addresses.
- List the pcap files with
ls session1-*.pcap. They are empty here (no traffic) and fill up in question 2.
Program
The five helper calls are the skeleton of every NS-3 script: nodes, channel plus devices, protocol stack, addresses, then run.
/*
* MCSL-223 Section 1, Session 1, Question 1
* Point-to-point topology with two nodes.
*
* Build: copy to ns-3.36+/scratch/ and run
* ./ns3 run scratch/p2p_two_nodes
*
* Topology:
* n0 ---------- n1
* 5 Mbps, 2 ms
* 10.1.1.1 10.1.1.2
*/
#include "ns3/core-module.h"
#include "ns3/network-module.h"
#include "ns3/internet-module.h"
#include "ns3/point-to-point-module.h"
using namespace ns3;
NS_LOG_COMPONENT_DEFINE("P2PTwoNodes");
/*
* main: creates two nodes, joins them with one point-to-point link,
* installs the IP stack, assigns 10.1.1.0/24 and prints what was built.
* No traffic is sent; question 2 adds the applications.
*/
int
main(int argc, char* argv[])
{
std::string dataRate = "5Mbps";
std::string delay = "2ms";
CommandLine cmd(__FILE__);
cmd.AddValue("dataRate", "Link data rate", dataRate);
cmd.AddValue("delay", "Link propagation delay", delay);
cmd.Parse(argc, argv);
// 1. Nodes: the two end hosts.
NodeContainer nodes;
nodes.Create(2);
// 2. Channel and net devices: one full-duplex point-to-point link.
PointToPointHelper p2p;
p2p.SetDeviceAttribute("DataRate", StringValue(dataRate));
p2p.SetChannelAttribute("Delay", StringValue(delay));
NetDeviceContainer devices = p2p.Install(nodes);
// 3. Protocol stack: IPv4, UDP, TCP on both nodes.
InternetStackHelper stack;
stack.Install(nodes);
// 4. Addresses: one /24 subnet for the link.
Ipv4AddressHelper address;
address.SetBase("10.1.1.0", "255.255.255.0");
Ipv4InterfaceContainer interfaces = address.Assign(devices);
// Report the topology so the lab record has something to show.
std::cout << "Nodes created : " << nodes.GetN() << std::endl;
std::cout << "Link : " << dataRate << ", delay " << delay << std::endl;
for (uint32_t i = 0; i < nodes.GetN(); ++i)
{
std::cout << "n" << i << " address : " << interfaces.GetAddress(i) << std::endl;
}
// Write a pcap per device (session1-0-0.pcap, session1-1-0.pcap).
p2p.EnablePcapAll("session1");
Simulator::Stop(Seconds(10.0));
Simulator::Run();
std::cout << "Simulation finished at " << Simulator::Now().GetSeconds() << " s" << std::endl;
Simulator::Destroy();
return 0;
}Output
Topology drawn for the record:
5 Mbit/s, 2 ms
n0 ------------------- n1
10.1.1.1 10.1.1.2
(10.1.1.0/24, one point-to-point channel)Expected console output (NS-3 is not installed on the machine that wrote this page, so values come from the parameters, not from a run):
Nodes created : 2
Link : 5Mbps, delay 2ms
n0 address : 10.1.1.1
n1 address : 10.1.1.2
Simulation finished at 10 sChange the link from the command line without editing the file: ./ns3 run "scratch/p2p_two_nodes --dataRate=10Mbps --delay=5ms".
Explanation
What each helper call creates, for the viva:
| Call | Objects created | Key attributes |
|---|---|---|
NodeContainer::Create(2) | two Node objects, ids 0 and 1 | none |
PointToPointHelper::Install | two PointToPointNetDevice, one PointToPointChannel, two DropTailQueue | DataRate (device), Delay (channel), MaxSize (queue, 100 packets) |
InternetStackHelper::Install | Ipv4L3Protocol, ArpL3Protocol, UdpL4Protocol, TcpL4Protocol, loopback device, list routing | IpForward true |
Ipv4AddressHelper::Assign | one Ipv4Interface per device with an address and mask | base 10.1.1.0, mask /24 |
EnablePcapAll | one pcap file per device | prefix session1 |
NodeContainer::Create(2) makes two empty nodes. PointToPointHelper::Install creates one PointToPointNetDevice on each node and a PointToPointChannel between them; DataRate lives on the device (it decides how long a packet takes to serialise) and Delay on the channel (propagation time). InternetStackHelper adds IPv4, ARP, UDP and TCP to both nodes. Ipv4AddressHelper::Assign hands out 10.1.1.1 and 10.1.1.2 in device order. Nothing is scheduled, so Simulator::Run returns as soon as the stop event at 10 s fires. From the formula sheet, one 1024-byte packet on this link takes to serialise (1024 bytes payload plus 8 UDP, 20 IP and 2 PPP header bytes) and to propagate, so ; question 2 shows exactly that number in the log.
Question 2
Problem Statement
Write in lab recordCreate a UdpClient and UdpServer nodes and communicate at a fixed data rate.
Solution
Write in lab recordSteps
- Pick the fixed rate: packet size = 1024 bytes and rate = 1 Mbit/s. From the formula sheet the client interval is .
- Save the program as
scratch/udp_echo_fixed_rate.ccand run./ns3 run scratch/udp_echo_fixed_rate. - Read the client and server log lines; NS-3 prints them because the script enables
LOG_LEVEL_INFOon both applications. - Open
session1-echo-1-0.pcapin Wireshark (n1’s device) and confirm 10 UDP packets in each direction with the filterudp.port == 9. - Try another rate:
./ns3 run "scratch/udp_echo_fixed_rate --rate=2000000 --maxPackets=20"halves the interval to 4.096 ms.
Intervals for other fixed rates with a 1024-byte packet, from the same formula:
| Rate | Interval | Command line |
|---|---|---|
| 500 kbit/s | 16.384 ms | --rate=500000 |
| 1 Mbit/s | 8.192 ms | default |
| 2 Mbit/s | 4.096 ms | --rate=2000000 |
| 4 Mbit/s | 2.048 ms | --rate=4000000 (80 percent of the 5 Mbit/s link) |
Program
/*
* MCSL-223 Section 1, Session 1, Question 2
* UDP echo client and server on the two-node link, sending at a fixed rate.
*
* Build: copy to ns-3.36+/scratch/ and run
* ./ns3 run scratch/udp_echo_fixed_rate
*
* Fixed data rate: packet size L = 1024 bytes, rate R = 1 Mbit/s,
* so the client interval is 8L/R = 8192 / 1e6 = 8.192 ms.
*
* n0 (client) ---------- n1 (server, port 9)
* 10.1.1.1 5 Mbps, 2 ms 10.1.1.2
*/
#include "ns3/core-module.h"
#include "ns3/network-module.h"
#include "ns3/internet-module.h"
#include "ns3/point-to-point-module.h"
#include "ns3/applications-module.h"
using namespace ns3;
NS_LOG_COMPONENT_DEFINE("UdpEchoFixedRate");
/*
* main: builds the Session 1 link, puts a UdpEchoServer on n1 and a
* UdpEchoClient on n0 that sends maxPackets packets of packetSize bytes
* every 8*packetSize/rate seconds, then runs for 10 s.
*/
int
main(int argc, char* argv[])
{
uint32_t packetSize = 1024; // bytes
uint32_t maxPackets = 10;
double rateBps = 1e6; // bit/s, the fixed data rate
CommandLine cmd(__FILE__);
cmd.AddValue("packetSize", "UDP payload in bytes", packetSize);
cmd.AddValue("maxPackets", "Packets the client sends", maxPackets);
cmd.AddValue("rate", "Client data rate in bit/s", rateBps);
cmd.Parse(argc, argv);
// Print the client and server log lines (the expected output).
LogComponentEnable("UdpEchoClientApplication", LOG_LEVEL_INFO);
LogComponentEnable("UdpEchoServerApplication", LOG_LEVEL_INFO);
NodeContainer nodes;
nodes.Create(2);
PointToPointHelper p2p;
p2p.SetDeviceAttribute("DataRate", StringValue("5Mbps"));
p2p.SetChannelAttribute("Delay", StringValue("2ms"));
NetDeviceContainer devices = p2p.Install(nodes);
InternetStackHelper stack;
stack.Install(nodes);
Ipv4AddressHelper address;
address.SetBase("10.1.1.0", "255.255.255.0");
Ipv4InterfaceContainer interfaces = address.Assign(devices);
// Server on n1, listening on UDP port 9.
UdpEchoServerHelper echoServer(9);
ApplicationContainer serverApps = echoServer.Install(nodes.Get(1));
serverApps.Start(Seconds(1.0));
serverApps.Stop(Seconds(10.0));
// Client on n0. Interval = 8L/R seconds gives the fixed rate.
double intervalUs = 8.0 * packetSize / rateBps * 1e6;
UdpEchoClientHelper echoClient(interfaces.GetAddress(1), 9);
echoClient.SetAttribute("MaxPackets", UintegerValue(maxPackets));
echoClient.SetAttribute("Interval", TimeValue(MicroSeconds(static_cast<uint64_t>(intervalUs))));
echoClient.SetAttribute("PacketSize", UintegerValue(packetSize));
ApplicationContainer clientApps = echoClient.Install(nodes.Get(0));
clientApps.Start(Seconds(2.0));
clientApps.Stop(Seconds(10.0));
std::cout << "Client rate " << rateBps / 1e6 << " Mbit/s, packet " << packetSize
<< " B, interval " << intervalUs / 1000.0 << " ms, packets " << maxPackets
<< std::endl;
p2p.EnablePcapAll("session1-echo");
Simulator::Run();
Simulator::Destroy();
return 0;
}Output
Expected output (first three and last exchanges shown; the remaining lines follow the same 8.192 ms spacing). Time stamps are computed from the link parameters: one-way delay is 1.686 ms serialisation plus 2 ms propagation, 3.686 ms.
Client rate 1 Mbit/s, packet 1024 B, interval 8.192 ms, packets 10
At time +2s client sent 1024 bytes to 10.1.1.2 port 9
At time +2.00369s server received 1024 bytes from 10.1.1.1 port 49153
At time +2.00369s server sent 1024 bytes to 10.1.1.1 port 49153
At time +2.00737s client received 1024 bytes from 10.1.1.2 port 9
At time +2.00819s client sent 1024 bytes to 10.1.1.2 port 9
At time +2.01188s server received 1024 bytes from 10.1.1.1 port 49153
At time +2.01188s server sent 1024 bytes to 10.1.1.1 port 49153
At time +2.01556s client received 1024 bytes from 10.1.1.2 port 9
At time +2.01638s client sent 1024 bytes to 10.1.1.2 port 9
At time +2.02007s server received 1024 bytes from 10.1.1.1 port 49153
At time +2.02007s server sent 1024 bytes to 10.1.1.1 port 49153
At time +2.02376s client received 1024 bytes from 10.1.1.2 port 9
...
At time +2.07373s client sent 1024 bytes to 10.1.1.2 port 9
At time +2.07741s server received 1024 bytes from 10.1.1.1 port 49153
At time +2.07741s server sent 1024 bytes to 10.1.1.1 port 49153
At time +2.0811s client received 1024 bytes from 10.1.1.2 port 9Calculation to show in the record:
| Quantity | Value |
|---|---|
| Packet size | 1024 bytes = 8192 bits |
| Fixed rate | 1 Mbit/s |
| Interval | 8.192 ms |
| One-way delay per packet | 1.686 ms + 2 ms = 3.686 ms |
| Round trip seen by the client | 7.37 ms |
| Bytes received at server | 10 x 1024 = 10240 |
| Server receive window | 2.00369 s to 2.07741 s = 73.7 ms |
| Measured throughput | 1.11 Mbit/s |
The measured value is 10/9 of the nominal 1 Mbit/s because ten packets span only nine intervals; with 1000 packets the ratio drops to 1.001.
Explanation
UdpEchoServerHelper(9) binds a UDP socket on port 9 of n1 and echoes every datagram back. UdpEchoClientHelper on n0 has three attributes that set the rate: PacketSize (bytes per datagram), Interval (time between datagrams) and MaxPackets (how many). Holding the size fixed and choosing the interval as gives a constant bit rate of exactly ; that is the same idea OnOffHelper uses internally in later sessions. The server starts at 1 s and the client at 2 s so the socket is listening before the first datagram arrives. Every log line carries the simulator time, which is why the record can show the transmission and propagation delay from the formula sheet appearing in the output.
Viva Questions
Do not copy. Read for understanding and the viva- Q: What is the difference between a Node, a NetDevice and a Channel? A: A Node is the computer, a NetDevice is its network card plus driver, a Channel is the wire between two devices.
- Q: Where is DataRate set and where is Delay set, and why? A: DataRate on the device because serialisation happens in the card; Delay on the channel because propagation happens on the wire.
- Q: Why does the server receive the first packet at 2.00369 s and not at 2.002 s? A: 2 ms is propagation only; 1054 bytes at 5 Mbit/s add 1.686 ms of serialisation.
- Q: How do you send at a fixed rate with UdpEchoClient? A: Fix PacketSize and set Interval to 8L/R seconds.
- Q: What does
Ipv4AddressHelper::Assignreturn? A: AnIpv4InterfaceContainer;GetAddress(i)gives the address of the i-th device in the container. - Q: Why start the server before the client? A: A datagram that arrives before the server socket is bound is dropped.
- Q: What is in
session1-echo-0-0.pcap? A: Every frame that entered or left device 0 of node 0, in libpcap format readable by Wireshark. - Q: Why does the client use port 49153? A: It is the first ephemeral port NS-3 allocates when a socket is bound without a port.
Common Mistakes
Do not copy. Read for understanding and the viva- Passing 8.192 to
MilliSeconds(); it takes an integer and silently rounds to 8 ms. UseMicroSeconds(8192). - Starting the client before or at the same time as the server, so the first datagram is lost.
- Forgetting
LogComponentEnable, then reporting that “nothing happens” because the run prints nothing. - Reading the pcap of the wrong node; the file name is prefix-nodeId-deviceId.
- Editing files under
examples/instead ofscratch/; onlyscratch/picks up new files without touching the build files. - Omitting the topology diagram from the record; the manual requires it with every program.
Formula Sheet
Do not copy. Read for understanding and the vivaThroughput
Bytes received at the sink divided by the time the flow was active, converted to bits per second:
Bandwidth-delay product
The amount of data in flight on a link of capacity and round-trip time . A TCP window smaller than this cannot fill the link:
For the Session 10 defaults, and one-way delay give and .
Transmission and propagation delay
where is packet size in bits, link rate, distance and signal speed (about in copper or fibre).
Constant bit rate traffic
An OnOff application with packet size bytes and rate bit/s sends one packet every
TCP congestion window
Slow start doubles the window every RTT until the threshold; congestion avoidance adds one segment per RTT; a loss halves it (TCP NewReno):
The maximum throughput of one TCP flow is bounded by
Packet loss
Session Summary
Write in lab recordp2p_two_nodes.cclisting with the header comment, the topology diagram and the address printoutudp_echo_fixed_rate.cclisting, the 40 echo log lines and the rate table (interval 8.192 ms for 1 Mbit/s, throughput 1.11 Mbit/s)- Wireshark screenshot of
session1-echo-1-0.pcapfiltered onudp.port == 9