This project uses NS-3 to simulate queueing theory concepts in a real network topology. Three clients send UDP traffic through a shared bottleneck link to a server, allowing observation of how packets queue, wait, get delayed, or get dropped under different network conditions.
The project covers three distinct queueing theory scenarios:
| Scenario | Concept | Key Parameter |
|---|---|---|
| 1 — Light Load | Stable queue (under-utilised M/M/1) | rate = 300Kbps, bottleneck = 2Mbps |
| 2 — Heavy Congestion | Saturated queue (overloaded M/M/1) | rate = 2Mbps, bottleneck = 1Mbps |
| 3 — Discipline Comparison | Priority vs Fair Queuing | qdisc = Prio then FqCodel |
ns-3-dev/
│
├── scratch/
│ └── queueing/
│ └── mm1-queueing.cc # Main NS3 simulation
│
├── results/ # Auto-created by simulation
│ ├── scenario1_lightLoad_stable/
│ │ ├── queue-size.tr # Queue depth trace
│ │ ├── flowmon.xml # Delay, throughput, loss data
│ │ ├── queueing.xml # NetAnim animation file
│ │ ├── plot_queue.png # Queue graph (generated by Python)
│ │ └── delay_analysis.png # Stats graph (generated by Python)
│ ├── scenario2_heavyLoad_congestion/
│ ├── scenario3_Prio/
│ ├── scenario3_FqCodel/
│ ├── plot_queue_comparison.png # All scenarios overlaid
│ └── plot_delay_comparison.png # All scenarios side by side
│
├── analysis/
│ ├── plot_queue.py # Queue length plots
│ └── plot_delay.py # Delay / throughput / loss plots
│
└── README.md
Verify it works:
cd ~/ns-3-dev
./ns3 --versionpip install matplotlib numpy lxml --break-system-packagessudo apt install netanimcp mm1-queueing.cc ~/ns-3-dev/scratch/queueing/mm1-queueing.cccp plot_queue.py ~/ns-3-dev/analysis/plot_queue.py
cp plot_delay.py ~/ns-3-dev/analysis/plot_delay.pymkdir -p ~/ns-3-dev/resultscd ~/ns-3-dev
./ns3 buildExpected output (no errors):
[ 0%] Building CXX object scratch/...
Finished executing the following commands:
/usr/bin/cmake --build ...
All commands are run from ~/ns-3-dev. Each run saves its output into its own subfolder
inside results/ so runs never overwrite each other.
Concept: Arrival rate is well below the bottleneck capacity. Queueing theory (M/M/1) predicts the queue stays near zero, delay is minimal, and no packets are lost.
./ns3 run scratch/queueing/mm1-queueing -- \
--rate=300Kbps \
--bottleneck=2Mbps \
--qdisc=Fifo \
--simTime=30 \
--tag=scenario1_lightLoad_stableWhat each flag does:
| Flag | Value | Meaning |
|---|---|---|
--rate |
300Kbps | Each client sends at 300 Kbps (900 Kbps total) |
--bottleneck |
2Mbps | Bottleneck link can carry 2 Mbps — more than enough |
--qdisc |
Fifo | Simple first-in-first-out queue, no prioritisation |
--simTime |
30 | Run for 30 seconds |
--tag |
scenario1_lightLoad_stable | Saves results to results/scenario1_lightLoad_stable/ |
Concept: Arrival rate far exceeds bottleneck capacity. Queueing theory predicts the queue fills completely, packets are dropped, delay spikes, and throughput collapses.
./ns3 run scratch/queueing/mm1-queueing -- \
--rate=2Mbps \
--bottleneck=1Mbps \
--qdisc=Fifo \
--simTime=30 \
--tag=scenario2_heavyLoad_congestionWhat each flag does:
| Flag | Value | Meaning |
|---|---|---|
--rate |
2Mbps | Each client sends at 2 Mbps (6 Mbps total) |
--bottleneck |
1Mbps | Bottleneck can only carry 1 Mbps — severe overload |
--qdisc |
Fifo | FIFO queue — no protection, fills and drops blindly |
--simTime |
30 | Run for 30 seconds to observe sustained congestion |
--tag |
scenario2_heavyLoad_congestion | Saves to results/scenario2_heavyLoad_congestion/ |
Concept: Moderate load (arrival ≈ capacity). Shows how the PrioQueueDisc scheduler serves smaller packets first, giving lower delay to Client 0 (512B) vs Client 2 (2048B).
./ns3 run scratch/queueing/mm1-queueing -- \
--rate=1Mbps \
--bottleneck=1Mbps \
--qdisc=Prio \
--pkt0=512 \
--pkt1=1024 \
--pkt2=2048 \
--simTime=30 \
--tag=scenario3_PrioWhat each flag does:
| Flag | Value | Meaning |
|---|---|---|
--rate |
1Mbps | Each client sends at 1 Mbps (3 Mbps total) |
--bottleneck |
1Mbps | Bottleneck at 1 Mbps — moderate pressure |
--qdisc |
Prio | Priority queue: smaller/higher-priority packets go first |
--pkt0/1/2 |
512/1024/2048 | Different packet sizes per client to make priority visible |
--simTime |
30 | 30 seconds |
--tag |
scenario3_Prio | Saves to results/scenario3_Prio/ |
Concept: Same load as Scenario 3a but using FqCoDelQueueDisc. FqCoDel gives each flow its own queue (fairness) and actively manages delay (AQM). Compare results directly with Scenario 3a to see the discipline effect.
./ns3 run scratch/queueing/mm1-queueing -- \
--rate=1Mbps \
--bottleneck=1Mbps \
--qdisc=FqCodel \
--pkt0=512 \
--pkt1=1024 \
--pkt2=2048 \
--simTime=30 \
--tag=scenario3_FqCodelWhat each flag does:
| Flag | Value | Meaning |
|---|---|---|
--rate |
1Mbps | Same as 3a — identical load for fair comparison |
--bottleneck |
1Mbps | Same bottleneck |
--qdisc |
FqCodel | Fair Queuing + CoDel AQM — reduces bufferbloat |
--pkt0/1/2 |
512/1024/2048 | Same packet sizes as 3a |
--simTime |
30 | 30 seconds |
--tag |
scenario3_FqCodel | Saves to results/scenario3_FqCodel/ |
After each run, check that the three output files were created:
ls -lh ~/ns-3-dev/results/scenario1_lightLoad_stable/
ls -lh ~/ns-3-dev/results/scenario2_heavyLoad_congestion/
ls -lh ~/ns-3-dev/results/scenario3_Prio/
ls -lh ~/ns-3-dev/results/scenario3_FqCodel/Each folder should contain:
queue-size.tr # timestamped queue depth events
flowmon.xml # per-flow delay, throughput, loss statistics
queueing.xml # NetAnim packet animation file
All analysis commands are run from the analysis/ directory:
cd ~/ns-3-dev/analysisSingle scenario — detailed two-panel chart (smooth line + raw events):
python3 plot_queue.py --tag scenario1_lightLoad_stable
python3 plot_queue.py --tag scenario2_heavyLoad_congestion
python3 plot_queue.py --tag scenario3_Prio
python3 plot_queue.py --tag scenario3_FqCodelEach saves a PNG to its own results subfolder:
results/scenario1_lightLoad_stable/plot_queue.png
results/scenario2_heavyLoad_congestion/plot_queue.png
results/scenario3_Prio/plot_queue.png
results/scenario3_FqCodel/plot_queue.png
All scenarios overlaid — comparison chart:
python3 plot_queue.py --compareSaves to:
results/plot_queue_comparison.png
Single scenario — 4-panel chart (delay, throughput, loss, summary table):
python3 plot_delay.py --tag scenario1_lightLoad_stable
python3 plot_delay.py --tag scenario2_heavyLoad_congestion
python3 plot_delay.py --tag scenario3_Prio
python3 plot_delay.py --tag scenario3_FqCodelEach saves to its own subfolder:
results/scenario1_lightLoad_stable/delay_analysis.png
results/scenario2_heavyLoad_congestion/delay_analysis.png
results/scenario3_Prio/delay_analysis.png
results/scenario3_FqCodel/delay_analysis.png
All scenarios side by side — grouped bar comparison:
python3 plot_delay.py --compareSaves to:
results/plot_delay_comparison.png
To run all four simulations and generate all graphs in one go:
cd ~/ns-3-dev
./ns3 run scratch/queueing/mm1-queueing -- --rate=300Kbps --bottleneck=2Mbps --qdisc=Fifo --simTime=30 --tag=scenario1_lightLoad_stable
./ns3 run scratch/queueing/mm1-queueing -- --rate=2Mbps --bottleneck=1Mbps --qdisc=Fifo --simTime=30 --tag=scenario2_heavyLoad_congestion
./ns3 run scratch/queueing/mm1-queueing -- --rate=1Mbps --bottleneck=1Mbps --qdisc=Prio --pkt0=512 --pkt1=1024 --pkt2=2048 --simTime=30 --tag=scenario3_Prio
./ns3 run scratch/queueing/mm1-queueing -- --rate=1Mbps --bottleneck=1Mbps --qdisc=FqCodel --pkt0=512 --pkt1=1024 --pkt2=2048 --simTime=30 --tag=scenario3_FqCodel
cd analysis
python3 plot_queue.py --tag scenario1_lightLoad_stable
python3 plot_queue.py --tag scenario2_heavyLoad_congestion
python3 plot_queue.py --tag scenario3_Prio
python3 plot_queue.py --tag scenario3_FqCodel
python3 plot_queue.py --compare
python3 plot_delay.py --tag scenario1_lightLoad_stable
python3 plot_delay.py --tag scenario2_heavyLoad_congestion
python3 plot_delay.py --tag scenario3_Prio
python3 plot_delay.py --tag scenario3_FqCodel
python3 plot_delay.py --compareOpen individual PNGs:
xdg-open ~/ns-3-dev/results/scenario1_lightLoad_stable/plot_queue.png
xdg-open ~/ns-3-dev/results/plot_queue_comparison.png
xdg-open ~/ns-3-dev/results/plot_delay_comparison.pngView the packet animation in NetAnim:
netanim ~/ns-3-dev/results/scenario1_lightLoad_stable/queueing.xmlList all generated graphs:
find ~/ns-3-dev/results -name "*.png"| Parameter | Default | Description |
|---|---|---|
--simTime |
15 | Total simulation duration in seconds |
--rate |
500Kbps | Data rate for each client OnOff application |
--bottleneck |
1Mbps | Bottleneck link capacity (router → server) |
--accessRate |
100Mbps | Client access link capacity |
--accessDelay |
2ms | Client access link one-way delay |
--bnDelay |
10ms | Bottleneck link one-way delay |
--qdisc |
Prio | Queue discipline: Prio, FqCodel, TBF, Fifo |
--pkt0 |
512 | Packet size for Client 0 in bytes |
--pkt1 |
1024 | Packet size for Client 1 in bytes |
--pkt2 |
2048 | Packet size for Client 2 in bytes |
--tag |
auto | Name for this experiment run (used as output folder name) |
If --tag is not provided, an automatic tag is generated from the parameters,
e.g. rate500Kbps_bn1Mbps_Prio.
Client 0 (512B) ─┐
│ 100Mbps/2ms 1Mbps/10ms
Client 1 (1024B) ──┤──────────────► Router ──────────────► Server
│ access links [queue disc] bottleneck
Client 2 (2048B) ─┘
- Clients send UDP traffic using an OnOff application (alternating on/off bursts)
- The router applies the selected queue discipline on the bottleneck link
- All three flows share the single 1Mbps (default) bottleneck — this is where queuing occurs
- The FlowMonitor measures per-flow statistics end-to-end
Clock skew warning during build:
gmake[3]: warning: Clock skew detected.
This is harmless. Fix it permanently with:
sudo hwclock --hctosysFigureCanvasAgg is non-interactive warning from Python:
This is expected in headless/SSH terminals. The scripts use the Agg backend which
writes directly to PNG — no display server needed. The PNG files are saved correctly.
lxml not found:
pip install lxml --break-system-packagesNo experiment subfolders found:
Make sure you ran the NS3 simulation first and that the results/ folder is inside
~/ns-3-dev/, not somewhere else.
Build fails with MobilityHelper not declared:
Make sure your mm1-queueing.cc has this include at the top:
#include "ns3/mobility-module.h"| File | Generated by | Contains |
|---|---|---|
queue-size.tr |
NS3 trace | Timestamped queue depth in packets — one row per change event |
flowmon.xml |
NS3 FlowMonitor | Per-flow: packets sent/received/lost, total bytes, delay sum, timestamps |
queueing.xml |
NS3 NetAnim | Full packet animation — open in the NetAnim GUI |
plot_queue.png |
plot_queue.py | Queue length over time — smooth line + raw event scatter |
delay_analysis.png |
plot_delay.py | Avg delay, throughput, packet loss per flow + summary table |
plot_queue_comparison.png |
plot_queue.py --compare | All scenarios overlaid on one chart |
plot_delay_comparison.png |
plot_delay.py --compare | All scenarios side by side grouped bars |