|
1 #include "ns3/network-module.h" |
|
2 #include "ns3/core-module.h" |
|
3 #include "ns3/internet-module.h" |
|
4 #include "ns3/dce-module.h" |
|
5 #include "ns3/point-to-point-module.h" |
|
6 #include "ns3/applications-module.h" |
|
7 |
|
8 using namespace ns3; |
|
9 |
|
10 // This is a test case for a couple of bugs that I found. |
|
11 // It mixes NS3 and DCE-LINUX nodes in a multi-hop network. DCE-linux assumes all nodes are running DCE-linux, but it shouldn't |
|
12 // It also allows setting memory available to TCP in DCE-Linux, and the requested iperf window size (-w option) |
|
13 |
|
14 |
|
15 NS_LOG_COMPONENT_DEFINE ("DceIperfMultihop"); |
|
16 // ====================================================================================================================================== |
|
17 // |
|
18 // < - - - - - - Left Side Links - - - - - > < - - CenterLink - - > < - - - - - Right Side Links - - - - - > |
|
19 // |
|
20 // client router1 router2 router N-1 router N server |
|
21 // +----------------+ +----------------+ +----------------+ +----------------+ +----------------+ +----------------+ |
|
22 // | iperf(Client) | | router | | router | | router | | router | | iperf(Server) | |
|
23 // +----------------+ +----------------+ +----------------+ ... +----------------+ +----------------+ +----------------+ |
|
24 // | DCE Linux | | NS3 | | NS3 | | NS3 | | NS3 | | DCE Linux | |
|
25 // +----------------+ +----------------+ +----------------+ +----------------+ +----------------+ +----------------+ |
|
26 // | 10.1.0.* | | 10.1.1.* | | 10.3.0.* | | 10.2.1.* | | 10.2.0.* | |
|
27 // +----------------+ +--------//------+ +----------//--------+ +---------------+ +----------------+ |
|
28 // point-to-point point-to-point point-to-point point-to-point point-to-point |
|
29 // fastLink slowLink slowLink slowLink fastLink |
|
30 // |
|
31 // ====================================================================================================================================== |
|
32 |
|
33 // ######################################################################## |
|
34 // Declare callbacks for printing Sysctl values |
|
35 // ######################################################################## |
|
36 static void PrintSysctlResult_client (std::string key, std::string value); |
|
37 static void PrintSysctlResult_server (std::string key, std::string value); |
|
38 |
|
39 int |
|
40 main (int argc, char *argv[]) |
|
41 { |
|
42 // ---------------------------------------------------------------------- |
|
43 // Defaults |
|
44 // ---------------------------------------------------------------------- |
|
45 std::string stack = "linux"; |
|
46 std::string slowLinkDataRate = "50Mbps"; |
|
47 std::string slowLinkDelay = "30ms"; |
|
48 uint32_t numRouters = 2; |
|
49 int iperfDurationSeconds = 120; |
|
50 |
|
51 uint32_t snapLen = PcapFile::SNAPLEN_DEFAULT; |
|
52 |
|
53 std::string tcp = ""; |
|
54 std::string clientTcp = ""; |
|
55 std::string serverTcp = ""; |
|
56 |
|
57 std::string netmem = ""; |
|
58 std::string clientNetmem = ""; |
|
59 std::string serverNetmem = ""; |
|
60 |
|
61 std::string tcpWin = "256k"; |
|
62 std::string clientTcpWin = ""; |
|
63 std::string serverTcpWin = ""; |
|
64 |
|
65 // ---------------------------------------------------------------------- |
|
66 // Create command line options and get them |
|
67 // ---------------------------------------------------------------------- |
|
68 CommandLine cmd; |
|
69 cmd.AddValue ("routers", "Number of routers between client&server. Default is 2.", numRouters); |
|
70 cmd.AddValue ("stack", "Name of IP stack: ns3/linux. Default is linux", stack); |
|
71 cmd.AddValue ("rate", "Slow link data rate. Default is 50Mbps.", slowLinkDataRate); |
|
72 cmd.AddValue ("delay", "Slow link delay. Default 50ms.", slowLinkDelay); |
|
73 cmd.AddValue ("duration", "Duration of iperf session. Default is 120.", iperfDurationSeconds); |
|
74 cmd.AddValue ("tcp", "Select TCP congestion alg for iPerf.", tcp); |
|
75 cmd.AddValue ("clientTcp", "Select TCP congestion alg for iPerf(client only).", clientTcp); |
|
76 cmd.AddValue ("serverTcp", "Select TCP congestion alg for iPerf(server only).", serverTcp); |
|
77 |
|
78 cmd.AddValue ("netmem", "Set dce-linux network memory using Sysctl", netmem); |
|
79 cmd.AddValue ("clientNetmem", "Set dce-linux network memory (on client only).", clientNetmem); |
|
80 cmd.AddValue ("serverNetmem", "Set dce-linux network memory (on server only).", serverNetmem); |
|
81 |
|
82 cmd.AddValue ("tcpWin", "Set dce-linux network memory using Sysctl (256k)", tcpWin); |
|
83 cmd.AddValue ("clientTcpWin", "Set dce-linux network memory (on client only).", clientTcpWin); |
|
84 cmd.AddValue ("serverTcpWin", "Set dce-linux network memory (on server only).", serverTcpWin); |
|
85 |
|
86 cmd.AddValue ("snapLen", "PCAP packet capture length", snapLen); |
|
87 |
|
88 cmd.Parse (argc, argv); |
|
89 |
|
90 // ---------------------------------------------------------------------- |
|
91 // Check command line options |
|
92 // ---------------------------------------------------------------------- |
|
93 if ( (numRouters < 2) || ((numRouters % 2) == 1)) |
|
94 { |
|
95 NS_LOG_ERROR ("ERROR: Number of routers must be even and no less than 2."); |
|
96 return 0; |
|
97 } |
|
98 |
|
99 std::ostringstream iperfDurationArg; |
|
100 iperfDurationArg << iperfDurationSeconds; |
|
101 |
|
102 // ---------------------------------------------------------------------- |
|
103 // Set all TCP stacks to use a common congestion control algorithm, if requested |
|
104 // ---------------------------------------------------------------------- |
|
105 if (tcp != "") |
|
106 { |
|
107 clientTcp = tcp; |
|
108 serverTcp = tcp; |
|
109 } |
|
110 |
|
111 |
|
112 // ---------------------------------------------------------------------- |
|
113 // Set all TCP window sizes, if requested |
|
114 // ---------------------------------------------------------------------- |
|
115 if (tcpWin != "") |
|
116 { |
|
117 clientTcpWin = tcpWin; |
|
118 serverTcpWin = tcpWin; |
|
119 } |
|
120 |
|
121 |
|
122 // ---------------------------------------------------------------------- |
|
123 // Set network memory for dce-linux using sysctl() |
|
124 // ---------------------------------------------------------------------- |
|
125 if (netmem != "") |
|
126 { |
|
127 clientNetmem = netmem; |
|
128 serverNetmem = netmem; |
|
129 } |
|
130 |
|
131 // ---------------------------------------------------------------------- |
|
132 // Set PCAP packet capture maximum packet length |
|
133 // ---------------------------------------------------------------------- |
|
134 Config::SetDefault ("ns3::PcapFileWrapper::CaptureSize", UintegerValue (snapLen)); |
|
135 |
|
136 // ---------------------------------------------------------------------- |
|
137 // Create nodes |
|
138 // ---------------------------------------------------------------------- |
|
139 Ptr<Node> client = CreateObject<Node> (); // 10.1.0.1 |
|
140 |
|
141 NodeContainer routersL, routersR; |
|
142 routersL.Create (numRouters/2); |
|
143 routersR.Create (numRouters/2); |
|
144 |
|
145 Ptr<Node> server = CreateObject<Node> (); // 10.3.0.1 |
|
146 |
|
147 // ---------------------------------------------------------------------- |
|
148 // Set some simulator-wide values |
|
149 // ---------------------------------------------------------------------- |
|
150 Config::SetDefault ("ns3::TcpSocket::SegmentSize", UintegerValue (1448)); |
|
151 GlobalValue::Bind ("ChecksumEnabled", BooleanValue (true)); |
|
152 |
|
153 DceManagerHelper dceManager; |
|
154 dceManager.SetTaskManagerAttribute ("FiberManagerType", StringValue ("UcontextFiberManager")); |
|
155 |
|
156 // ---------------------------------------------------------------------- |
|
157 // Install the internet stack on each node |
|
158 // client and server endpoints are selectable: ns3 or DCE linux (2.6.36) |
|
159 // intermediate routers get NS3 |
|
160 // ---------------------------------------------------------------------- |
|
161 InternetStackHelper ns3stack; |
|
162 ns3stack.Install (routersL); |
|
163 ns3stack.Install (routersR); |
|
164 |
|
165 #ifdef KERNEL_STACK |
|
166 LinuxStackHelper linuxStack; |
|
167 #endif |
|
168 |
|
169 if (stack == "ns3") |
|
170 { |
|
171 ns3stack.Install (client); |
|
172 ns3stack.Install (server); |
|
173 dceManager.Install (client); |
|
174 dceManager.Install (server); |
|
175 } |
|
176 else if (stack == "linux") |
|
177 { |
|
178 #ifdef KERNEL_STACK |
|
179 dceManager.SetNetworkStack ("ns3::LinuxSocketFdFactory", "Library", StringValue ("liblinux.so")); |
|
180 dceManager.Install (client); |
|
181 dceManager.Install (server); |
|
182 linuxStack.Install (client); |
|
183 linuxStack.Install (server); |
|
184 #else |
|
185 NS_LOG_ERROR ("Linux kernel stack for DCE is not available. Re-build with the dce-linux module."); |
|
186 // silently exit |
|
187 return 0; |
|
188 #endif |
|
189 } |
|
190 |
|
191 // ---------------------------------------------------------------------- |
|
192 // Create fast and slow link types |
|
193 // ---------------------------------------------------------------------- |
|
194 Ipv4AddressHelper address; |
|
195 |
|
196 PointToPointHelper fastLink; |
|
197 fastLink.SetDeviceAttribute ("DataRate", StringValue ("1Gbps")); |
|
198 fastLink.SetChannelAttribute("Delay", StringValue ("1.0us")); |
|
199 |
|
200 PointToPointHelper slowLink; |
|
201 slowLink.SetDeviceAttribute ("DataRate", StringValue (slowLinkDataRate)); |
|
202 slowLink.SetChannelAttribute("Delay", StringValue (slowLinkDelay)); |
|
203 |
|
204 // ---------------------------------------------------------------------- |
|
205 // Make left side fast connection and assign addresses (10.1.i.*/24) |
|
206 // ---------------------------------------------------------------------- |
|
207 NetDeviceContainer linkL[numRouters/2]; |
|
208 |
|
209 linkL[0] = fastLink.Install (client, routersL.Get(0)); |
|
210 address.SetBase ("10.1.0.0", "255.255.255.0"); |
|
211 address.Assign (linkL[0]); |
|
212 |
|
213 // ---------------------------------------------------------------------- |
|
214 // Make extra left side slow connections and assign addresses (10.1.i.*/24) |
|
215 // ---------------------------------------------------------------------- |
|
216 for(int i=1; i<numRouters/2; i++) |
|
217 { |
|
218 linkL[i] = slowLink.Install (routersL.Get(i-1), routersL.Get(i)); |
|
219 |
|
220 std::ostringstream oss; |
|
221 oss << "10.1." << i << ".0"; |
|
222 address.SetBase (oss.str ().c_str (), "255.255.255.0"); |
|
223 address.Assign (linkL[i]); |
|
224 } |
|
225 |
|
226 // ---------------------------------------------------------------------- |
|
227 // Make slow connection in the middle and assign addresses (10.2.0.*/24) |
|
228 // ---------------------------------------------------------------------- |
|
229 NetDeviceContainer linkM; |
|
230 linkM = slowLink.Install (routersL.Get(numRouters/2-1), routersR.Get(numRouters/2-1)); |
|
231 |
|
232 address.SetBase ("10.2.0.0", "255.255.255.0"); |
|
233 address.Assign (linkM); |
|
234 |
|
235 // ---------------------------------------------------------------------- |
|
236 // Make extra right side slow connections and assign addresses (10.1.i.*/24) |
|
237 // ---------------------------------------------------------------------- |
|
238 NetDeviceContainer linkR[numRouters/2]; |
|
239 |
|
240 for(int i=1; i<numRouters/2; i++) |
|
241 { |
|
242 linkR[i] = slowLink.Install (routersR.Get(i-1), routersR.Get(i)); |
|
243 |
|
244 std::ostringstream oss; |
|
245 oss << "10.3." << i << ".0"; |
|
246 address.SetBase (oss.str ().c_str (), "255.255.255.0"); |
|
247 address.Assign (linkR[i]); |
|
248 } |
|
249 |
|
250 // ---------------------------------------------------------------------- |
|
251 // Make right side fast connections and assign addresses (10.3.i.*/24) |
|
252 // ---------------------------------------------------------------------- |
|
253 linkR[0] = fastLink.Install (server, routersR.Get(0)); |
|
254 address.SetBase ("10.3.0.0", "255.255.255.0"); |
|
255 address.Assign (linkR[0]); |
|
256 |
|
257 |
|
258 // ---------------------------------------------------------------------- |
|
259 // Calculate and populate routing tables |
|
260 // ---------------------------------------------------------------------- |
|
261 Ipv4GlobalRoutingHelper::PopulateRoutingTables (); |
|
262 #ifdef KERNEL_STACK |
|
263 if (stack == "linux") |
|
264 { |
|
265 LinuxStackHelper::PopulateRoutingTables (); |
|
266 } |
|
267 #endif |
|
268 |
|
269 // ---------------------------------------------------------------------- |
|
270 // Launch iperf client on client |
|
271 // ---------------------------------------------------------------------- |
|
272 DceApplicationHelper dce; |
|
273 ApplicationContainer apps; |
|
274 |
|
275 dce.SetStackSize (1 << 20); |
|
276 |
|
277 dce.SetBinary ("iperf"); |
|
278 dce.ResetArguments (); |
|
279 dce.ResetEnvironment (); |
|
280 dce.AddArgument ("-c"); |
|
281 dce.AddArgument ("10.3.0.1"); |
|
282 dce.AddArgument ("-i"); |
|
283 dce.AddArgument ("1"); |
|
284 dce.AddArgument ("--time"); |
|
285 dce.AddArgument (iperfDurationArg.str().c_str()); |
|
286 |
|
287 if (clientTcpWin != "") |
|
288 { |
|
289 dce.AddArgument ("-w"); |
|
290 dce.AddArgument (clientTcpWin); |
|
291 } |
|
292 |
|
293 apps = dce.Install (client); |
|
294 apps.Start (Seconds (0.75)); |
|
295 apps.Stop (Seconds (iperfDurationSeconds+3.0)); |
|
296 |
|
297 #ifdef KERNEL_STACK |
|
298 if (stack == "linux") |
|
299 { |
|
300 if(clientTcp != "") |
|
301 { |
|
302 linuxStack.SysctlSet (client,".net.ipv4.tcp_allowed_congestion_control", clientTcp); // done at 0.1 seconds |
|
303 linuxStack.SysctlSet (client,".net.ipv4.tcp_congestion_control", clientTcp); |
|
304 } |
|
305 |
|
306 LinuxStackHelper::SysctlGet (client, Seconds (0.11), |
|
307 ".net.ipv4.tcp_congestion_control", &PrintSysctlResult_client); |
|
308 |
|
309 if(clientNetmem != "") |
|
310 { |
|
311 linuxStack.SysctlSet (client, ".net.core.wmem_default", clientNetmem); // done at 0.1 seconds |
|
312 linuxStack.SysctlSet (client, ".net.core.wmem_max", clientNetmem); |
|
313 linuxStack.SysctlSet (client, ".net.core.rmem_default", clientNetmem); |
|
314 linuxStack.SysctlSet (client, ".net.core.rmem_max", clientNetmem); |
|
315 } |
|
316 |
|
317 LinuxStackHelper::SysctlGet (client, Seconds (0.11), |
|
318 ".net.core.wmem_max", &PrintSysctlResult_client); |
|
319 LinuxStackHelper::SysctlGet (client, Seconds (0.11), |
|
320 ".net.core.wmem_default", &PrintSysctlResult_client); |
|
321 LinuxStackHelper::SysctlGet (client, Seconds (0.11), |
|
322 ".net.core.rmem_max", &PrintSysctlResult_client); |
|
323 LinuxStackHelper::SysctlGet (client, Seconds (0.11), |
|
324 ".net.core.rmem_default", &PrintSysctlResult_client); |
|
325 } |
|
326 #endif |
|
327 |
|
328 // ---------------------------------------------------------------------- |
|
329 // Launch iperf server on server |
|
330 // ---------------------------------------------------------------------- |
|
331 dce.SetBinary ("iperf"); |
|
332 dce.ResetArguments (); |
|
333 dce.ResetEnvironment (); |
|
334 dce.AddArgument ("-s"); |
|
335 dce.AddArgument ("-P"); |
|
336 dce.AddArgument ("1"); |
|
337 |
|
338 if (serverTcpWin != "") |
|
339 { |
|
340 dce.AddArgument ("-w"); |
|
341 dce.AddArgument (serverTcpWin); |
|
342 } |
|
343 |
|
344 apps = dce.Install (server); |
|
345 apps.Start (Seconds (0.5)); |
|
346 apps.Stop (Seconds (iperfDurationSeconds+3.0)); |
|
347 |
|
348 #ifdef KERNEL_STACK |
|
349 if (stack == "linux") |
|
350 { |
|
351 if (serverTcp != "") |
|
352 { |
|
353 linuxStack.SysctlSet (server,".net.ipv4.tcp_allowed_congestion_control", serverTcp); |
|
354 linuxStack.SysctlSet (server,".net.ipv4.tcp_congestion_control", serverTcp); |
|
355 } |
|
356 |
|
357 LinuxStackHelper::SysctlGet (server, Seconds (0.12), |
|
358 ".net.ipv4.tcp_congestion_control", &PrintSysctlResult_server); |
|
359 |
|
360 if(serverNetmem != "") |
|
361 { |
|
362 linuxStack.SysctlSet (server, ".net.core.wmem_default", serverNetmem); // done at 0.1 seconds |
|
363 linuxStack.SysctlSet (server, ".net.core.wmem_max", serverNetmem); |
|
364 linuxStack.SysctlSet (server, ".net.core.rmem_default", serverNetmem); |
|
365 linuxStack.SysctlSet (server, ".net.core.rmem_max", serverNetmem); |
|
366 } |
|
367 |
|
368 LinuxStackHelper::SysctlGet (server, Seconds (0.12), |
|
369 ".net.core.wmem_max", &PrintSysctlResult_server); |
|
370 LinuxStackHelper::SysctlGet (server, Seconds (0.12), |
|
371 ".net.core.wmem_default", &PrintSysctlResult_server); |
|
372 LinuxStackHelper::SysctlGet (server, Seconds (0.12), |
|
373 ".net.core.rmem_max", &PrintSysctlResult_server); |
|
374 LinuxStackHelper::SysctlGet (server, Seconds (0.12), |
|
375 ".net.core.rmem_default", &PrintSysctlResult_server); |
|
376 } |
|
377 #endif |
|
378 |
|
379 // ---------------------------------------------------------------------- |
|
380 // print routing tables |
|
381 // ---------------------------------------------------------------------- |
|
382 Ipv4GlobalRoutingHelper g; |
|
383 Ptr<OutputStreamWrapper> routingStream = Create<OutputStreamWrapper> ("all_the.routes", std::ios::out); |
|
384 g.PrintRoutingTableAllAt (Seconds (0), routingStream); |
|
385 |
|
386 // ---------------------------------------------------------------------- |
|
387 // Capture packets on the links |
|
388 // ---------------------------------------------------------------------- |
|
389 fastLink.EnablePcap ("client.pcap", linkL[0].Get(0), true, true); // promiscuous=true, explicitFilename=true |
|
390 //fastLink.EnablePcap ("server.pcap", linkR[0].Get(0), true, true); // promiscuous=true, explicitFilename=true |
|
391 |
|
392 apps.Start (Seconds (0.6)); |
|
393 |
|
394 Simulator::Stop (Seconds (iperfDurationSeconds + 10.0)); |
|
395 Simulator::Run (); |
|
396 Simulator::Destroy (); |
|
397 |
|
398 return 0; |
|
399 } |
|
400 |
|
401 // ######################################################################## |
|
402 // Callbacks for printing Sysctl values |
|
403 // ######################################################################## |
|
404 static void |
|
405 PrintSysctlResult(std::string nodename, std::string key, std::string value) |
|
406 { |
|
407 std::cout << "SYSCTL(" |
|
408 << nodename |
|
409 << "): " |
|
410 << key |
|
411 << " => " |
|
412 << value; |
|
413 } |
|
414 |
|
415 static void |
|
416 PrintSysctlResult_client (std::string key, std::string value) |
|
417 { |
|
418 PrintSysctlResult("client",key,value); |
|
419 } |
|
420 |
|
421 static void |
|
422 PrintSysctlResult_server (std::string key, std::string value) |
|
423 { |
|
424 PrintSysctlResult("server",key,value); |
|
425 } |