example/dce-iperf-heterogeneous-multihop.cc
changeset 668 06b23f4d262c
child 722 d7a01c8b1a39
equal deleted inserted replaced
667:7b619c485f9f 668:06b23f4d262c
       
     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 }