-
Notifications
You must be signed in to change notification settings - Fork 18
/
Copy pathlab-2-solved.cc
334 lines (269 loc) · 9.05 KB
/
lab-2-solved.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
LAB Assignment #2
1. Create a simple dumbbell topology, two client Node1 and Node2 on
the left side of the dumbbell and server nodes Node3 and Node4 on the
right side of the dumbbell. Let Node5 and Node6 form the bridge of the
dumbbell. Use point to point links.
2. Install a TCP socket instance on Node1 that will connect to Node3.
3. Install a UDP socket instance on Node2 that will connect to Node4.
4. Start the TCP application at time 1s.
5. Start the UDP application at time 20s at rate Rate1 such that it clogs
half the dumbbell bridge's link capacity.
6. Increase the UDP application's rate at time 30s to rate Rate2
such that it clogs the whole of the dumbbell bridge's capacity.
7. Use the ns-3 tracing mechanism to record changes in congestion window
size of the TCP instance over time. Use gnuplot/matplotlib to visualise plots of cwnd vs time.
8. Mark points of fast recovery and slow start in the graphs.
9. Perform the above experiment for TCP variants Tahoe, Reno and New Reno,
all of which are available with ns-3.
Solution by: Konstantinos Katsaros (K.Katsaros@surrey.ac.uk)
based on fifth.cc
*/
// Network topology
//
// n0 ---+ +--- n2
// | |
// n4 -- n5
// | |
// n1 ---+ +--- n3
//
// - All links are P2P with 500kb/s and 2ms
// - TCP flow form n0 to n2
// - UDP flow from n1 to n3
#include <fstream>
#include <string>
#include "ns3/core-module.h"
#include "ns3/network-module.h"
#include "ns3/point-to-point-module.h"
#include "ns3/applications-module.h"
#include "ns3/internet-module.h"
#include "ns3/flow-monitor-module.h"
#include "ns3/ipv4-global-routing-helper.h"
using namespace ns3;
NS_LOG_COMPONENT_DEFINE ("Lab2");
class MyApp : public Application
{
public:
MyApp ();
virtual ~MyApp();
void Setup (Ptr<Socket> socket, Address address, uint32_t packetSize, uint32_t nPackets, DataRate dataRate);
void ChangeRate(DataRate newrate);
private:
virtual void StartApplication (void);
virtual void StopApplication (void);
void ScheduleTx (void);
void SendPacket (void);
Ptr<Socket> m_socket;
Address m_peer;
uint32_t m_packetSize;
uint32_t m_nPackets;
DataRate m_dataRate;
EventId m_sendEvent;
bool m_running;
uint32_t m_packetsSent;
};
MyApp::MyApp ()
: m_socket (0),
m_peer (),
m_packetSize (0),
m_nPackets (0),
m_dataRate (0),
m_sendEvent (),
m_running (false),
m_packetsSent (0)
{
}
MyApp::~MyApp()
{
m_socket = 0;
}
void
MyApp::Setup (Ptr<Socket> socket, Address address, uint32_t packetSize, uint32_t nPackets, DataRate dataRate)
{
m_socket = socket;
m_peer = address;
m_packetSize = packetSize;
m_nPackets = nPackets;
m_dataRate = dataRate;
}
void
MyApp::StartApplication (void)
{
m_running = true;
m_packetsSent = 0;
m_socket->Bind ();
m_socket->Connect (m_peer);
SendPacket ();
}
void
MyApp::StopApplication (void)
{
m_running = false;
if (m_sendEvent.IsRunning ())
{
Simulator::Cancel (m_sendEvent);
}
if (m_socket)
{
m_socket->Close ();
}
}
void
MyApp::SendPacket (void)
{
Ptr<Packet> packet = Create<Packet> (m_packetSize);
m_socket->Send (packet);
if (++m_packetsSent < m_nPackets)
{
ScheduleTx ();
}
}
void
MyApp::ScheduleTx (void)
{
if (m_running)
{
Time tNext (Seconds (m_packetSize * 8 / static_cast<double> (m_dataRate.GetBitRate ())));
m_sendEvent = Simulator::Schedule (tNext, &MyApp::SendPacket, this);
}
}
void
MyApp::ChangeRate(DataRate newrate)
{
m_dataRate = newrate;
return;
}
static void
CwndChange (uint32_t oldCwnd, uint32_t newCwnd)
{
std::cout << Simulator::Now ().GetSeconds () << "\t" << newCwnd <<"\n";
}
void
IncRate (Ptr<MyApp> app, DataRate rate)
{
app->ChangeRate(rate);
return;
}
int main (int argc, char *argv[])
{
std::string lat = "2ms";
std::string rate = "500kb/s"; // P2P link
bool enableFlowMonitor = false;
CommandLine cmd;
cmd.AddValue ("latency", "P2P link Latency in miliseconds", lat);
cmd.AddValue ("rate", "P2P data rate in bps", rate);
cmd.AddValue ("EnableMonitor", "Enable Flow Monitor", enableFlowMonitor);
cmd.Parse (argc, argv);
//
// Explicitly create the nodes required by the topology (shown above).
//
NS_LOG_INFO ("Create nodes.");
NodeContainer c; // ALL Nodes
c.Create(6);
NodeContainer n0n4 = NodeContainer (c.Get (0), c.Get (4));
NodeContainer n1n4 = NodeContainer (c.Get (1), c.Get (4));
NodeContainer n2n5 = NodeContainer (c.Get (2), c.Get (5));
NodeContainer n3n5 = NodeContainer (c.Get (3), c.Get (5));
NodeContainer n4n5 = NodeContainer (c.Get (4), c.Get (5));
//
// Install Internet Stack
//
InternetStackHelper internet;
internet.Install (c);
// We create the channels first without any IP addressing information
NS_LOG_INFO ("Create channels.");
PointToPointHelper p2p;
p2p.SetDeviceAttribute ("DataRate", StringValue (rate));
p2p.SetChannelAttribute ("Delay", StringValue (lat));
NetDeviceContainer d0d4 = p2p.Install (n0n4);
NetDeviceContainer d1d4 = p2p.Install (n1n4);
NetDeviceContainer d4d5 = p2p.Install (n4n5);
NetDeviceContainer d2d5 = p2p.Install (n2n5);
NetDeviceContainer d3d5 = p2p.Install (n3n5);
// Later, we add IP addresses.
NS_LOG_INFO ("Assign IP Addresses.");
Ipv4AddressHelper ipv4;
ipv4.SetBase ("10.1.1.0", "255.255.255.0");
Ipv4InterfaceContainer i0i4 = ipv4.Assign (d0d4);
ipv4.SetBase ("10.1.2.0", "255.255.255.0");
Ipv4InterfaceContainer i1i4 = ipv4.Assign (d1d4);
ipv4.SetBase ("10.1.3.0", "255.255.255.0");
Ipv4InterfaceContainer i4i5 = ipv4.Assign (d4d5);
ipv4.SetBase ("10.1.4.0", "255.255.255.0");
Ipv4InterfaceContainer i2i5 = ipv4.Assign (d2d5);
ipv4.SetBase ("10.1.5.0", "255.255.255.0");
Ipv4InterfaceContainer i3i5 = ipv4.Assign (d3d5);
NS_LOG_INFO ("Enable static global routing.");
//
// Turn on global static routing so we can actually be routed across the network.
//
Ipv4GlobalRoutingHelper::PopulateRoutingTables ();
NS_LOG_INFO ("Create Applications.");
// TCP connfection from N0 to N2
uint16_t sinkPort = 8080;
Address sinkAddress (InetSocketAddress (i2i5.GetAddress (0), sinkPort)); // interface of n2
PacketSinkHelper packetSinkHelper ("ns3::TcpSocketFactory", InetSocketAddress (Ipv4Address::GetAny (), sinkPort));
ApplicationContainer sinkApps = packetSinkHelper.Install (c.Get (2)); //n2 as sink
sinkApps.Start (Seconds (0.));
sinkApps.Stop (Seconds (100.));
Ptr<Socket> ns3TcpSocket = Socket::CreateSocket (c.Get (0), TcpSocketFactory::GetTypeId ()); //source at n0
// Trace Congestion window
ns3TcpSocket->TraceConnectWithoutContext ("CongestionWindow", MakeCallback (&CwndChange));
// Create TCP application at n0
Ptr<MyApp> app = CreateObject<MyApp> ();
app->Setup (ns3TcpSocket, sinkAddress, 1040, 100000, DataRate ("250Kbps"));
c.Get (0)->AddApplication (app);
app->SetStartTime (Seconds (1.));
app->SetStopTime (Seconds (100.));
// UDP connfection from N1 to N3
uint16_t sinkPort2 = 6;
Address sinkAddress2 (InetSocketAddress (i3i5.GetAddress (0), sinkPort2)); // interface of n3
PacketSinkHelper packetSinkHelper2 ("ns3::UdpSocketFactory", InetSocketAddress (Ipv4Address::GetAny (), sinkPort2));
ApplicationContainer sinkApps2 = packetSinkHelper2.Install (c.Get (3)); //n3 as sink
sinkApps2.Start (Seconds (0.));
sinkApps2.Stop (Seconds (100.));
Ptr<Socket> ns3UdpSocket = Socket::CreateSocket (c.Get (1), UdpSocketFactory::GetTypeId ()); //source at n1
// Create UDP application at n1
Ptr<MyApp> app2 = CreateObject<MyApp> ();
app2->Setup (ns3UdpSocket, sinkAddress2, 1040, 100000, DataRate ("250Kbps"));
c.Get (1)->AddApplication (app2);
app2->SetStartTime (Seconds (20.));
app2->SetStopTime (Seconds (100.));
// Increase UDP Rate
Simulator::Schedule (Seconds(30.0), &IncRate, app2, DataRate("500kbps"));
// Flow Monitor
Ptr<FlowMonitor> flowmon;
if (enableFlowMonitor)
{
FlowMonitorHelper flowmonHelper;
flowmon = flowmonHelper.InstallAll ();
}
//
// Now, do the actual simulation.
//
NS_LOG_INFO ("Run Simulation.");
Simulator::Stop (Seconds(100.0));
Simulator::Run ();
if (enableFlowMonitor)
{
flowmon->CheckForLostPackets ();
flowmon->SerializeToXmlFile("lab-2.flowmon", true, true);
}
Simulator::Destroy ();
NS_LOG_INFO ("Done.");
}