1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * This program is free software; you can redistribute it and/or modify
4  * it under the terms of the GNU General Public License version 2 as
5  * published by the Free Software Foundation;
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software
14  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
15  *
16  * Author: Duy Nguyen <duy@soe.ucsc.edu>
17  */
18 
19 /**
20  * Scenarios: 100 nodes, multiple simultaneous flows, multi-hop ad hoc, routing,
21  * and mobility
22  *
23  * QUICK INSTRUCTIONS:
24  *
25  * To optimize build:
26  * ./waf -d optimized configure
27  * ./waf
28  *
29  * To compile:
30  * ./waf --run wifi-multirate
31  *
32  * To compile with command line(useful for varying parameters):
33  * ./waf --run "wifi-multirate --totalTime=0.3s --rateManager=ns3::MinstrelWifiManager"
34  *
35  * To turn on NS_LOG:
36  * export NS_LOG=multirate=level_all
37  * (can only view log if built with ./waf -d debug configure)
38  *
39  * To debug:
40  * ./waf --shell
41  * gdb ./build/debug/examples/wireless/wifi-multirate
42  *
43  * To view pcap files:
44  * tcpdump -nn -tt -r filename.pcap
45  *
46  * To monitor the files:
47  * tail -f filename.pcap
48  *
49  */
50 
51 #include "ns3/gnuplot.h"
52 #include "ns3/command-line.h"
53 #include "ns3/config.h"
54 #include "ns3/uinteger.h"
55 #include "ns3/boolean.h"
56 #include "ns3/double.h"
57 #include "ns3/string.h"
58 #include "ns3/log.h"
59 #include "ns3/yans-wifi-helper.h"
60 #include "ns3/mobility-helper.h"
61 #include "ns3/internet-stack-helper.h"
62 #include "ns3/ipv4-address-helper.h"
63 #include "ns3/on-off-helper.h"
64 #include "ns3/yans-wifi-channel.h"
65 #include "ns3/mobility-model.h"
66 #include "ns3/olsr-helper.h"
67 #include "ns3/ipv4-static-routing-helper.h"
68 #include "ns3/ipv4-list-routing-helper.h"
69 #include "ns3/rectangle.h"
70 #include "ns3/flow-monitor-helper.h"
71 
72 using namespace ns3;
73 
74 NS_LOG_COMPONENT_DEFINE ("multirate");
75 
76 class Experiment
77 {
78 public:
79   Experiment ();
80   Experiment (std::string name);
81   Gnuplot2dDataset Run (const WifiHelper &wifi, const YansWifiPhyHelper &wifiPhy,
82                         const WifiMacHelper &wifiMac, const YansWifiChannelHelper &wifiChannel, const MobilityHelper &mobility);
83 
84   bool CommandSetup (int argc, char **argv);
IsRouting()85   bool IsRouting ()
86   {
87     return (enableRouting == 1) ? 1 : 0;
88   }
IsMobility()89   bool IsMobility ()
90   {
91     return (enableMobility == 1) ? 1 : 0;
92   }
93 
GetScenario()94   uint32_t GetScenario ()
95   {
96     return scenario;
97   }
98 
GetRtsThreshold()99   std::string GetRtsThreshold ()
100   {
101     return rtsThreshold;
102   }
GetOutputFileName()103   std::string GetOutputFileName ()
104   {
105     return outputFileName;
106   }
GetRateManager()107   std::string GetRateManager ()
108   {
109     return rateManager;
110   }
111 
112 private:
113   Ptr<Socket> SetupPacketReceive (Ptr<Node> node);
114   NodeContainer GenerateNeighbors (NodeContainer c, uint32_t senderId);
115 
116   void ApplicationSetup (Ptr<Node> client, Ptr<Node> server, double start, double stop);
117   void AssignNeighbors (NodeContainer c);
118   void SelectSrcDest (NodeContainer c);
119   void ReceivePacket (Ptr<Socket> socket);
120   void CheckThroughput ();
121   void SendMultiDestinations (Ptr<Node> sender, NodeContainer c);
122 
123   Gnuplot2dDataset m_output;
124 
125   double totalTime;
126   double expMean;
127   double samplingPeriod;
128 
129   uint32_t bytesTotal;
130   uint32_t packetSize;
131   uint32_t gridSize;
132   uint32_t nodeDistance;
133   uint32_t port;
134   uint32_t scenario;
135 
136   bool enablePcap;
137   bool enableTracing;
138   bool enableFlowMon;
139   bool enableRouting;
140   bool enableMobility;
141 
142   NodeContainer containerA, containerB, containerC, containerD;
143   std::string rtsThreshold, rateManager, outputFileName;
144 };
145 
Experiment()146 Experiment::Experiment ()
147 {
148 }
149 
Experiment(std::string name)150 Experiment::Experiment (std::string name)
151   : m_output (name),
152     totalTime (0.3),
153     expMean (0.1),
154     //flows being exponentially distributed
155     samplingPeriod (0.1),
156     bytesTotal (0),
157     packetSize (2000),
158     gridSize (10),
159     //10x10 grid  for a total of 100 nodes
160     nodeDistance (30),
161     port (5000),
162     scenario (4),
163     enablePcap (false),
164     enableTracing (true),
165     enableFlowMon (false),
166     enableRouting (false),
167     enableMobility (false),
168     rtsThreshold ("2200"),
169     //0 for enabling rts/cts
170     rateManager ("ns3::MinstrelWifiManager"),
171     outputFileName ("minstrel")
172 {
173   m_output.SetStyle (Gnuplot2dDataset::LINES);
174 }
175 
176 Ptr<Socket>
SetupPacketReceive(Ptr<Node> node)177 Experiment::SetupPacketReceive (Ptr<Node> node)
178 {
179   TypeId tid = TypeId::LookupByName ("ns3::UdpSocketFactory");
180   Ptr<Socket> sink = Socket::CreateSocket (node, tid);
181   InetSocketAddress local = InetSocketAddress (Ipv4Address::GetAny (), port);
182   sink->Bind (local);
183   sink->SetRecvCallback (MakeCallback (&Experiment::ReceivePacket, this));
184 
185   return sink;
186 }
187 
188 void
ReceivePacket(Ptr<Socket> socket)189 Experiment::ReceivePacket (Ptr<Socket> socket)
190 {
191   Ptr<Packet> packet;
192   while ((packet = socket->Recv ()))
193     {
194       bytesTotal += packet->GetSize ();
195     }
196 }
197 
198 void
CheckThroughput()199 Experiment::CheckThroughput ()
200 {
201   double mbs = ((bytesTotal * 8.0) / 1000000 / samplingPeriod);
202   bytesTotal = 0;
203   m_output.Add ((Simulator::Now ()).GetSeconds (), mbs);
204 
205   //check throughput every samplingPeriod second
206   Simulator::Schedule (Seconds (samplingPeriod), &Experiment::CheckThroughput, this);
207 }
208 
209 /**
210  *
211  * Take the grid map, divide it into 4 quadrants
212  * Assign all nodes from each quadrant to a specific container
213  *
214  */
215 void
AssignNeighbors(NodeContainer c)216 Experiment::AssignNeighbors (NodeContainer c)
217 {
218   uint32_t totalNodes = c.GetN ();
219   for (uint32_t i = 0; i < totalNodes; i++)
220     {
221       if ( (i % gridSize) <= (gridSize / 2 - 1))
222         {
223           //lower left quadrant
224           if ( i < totalNodes / 2 )
225             {
226               containerA.Add (c.Get (i));
227             }
228 
229           //upper left quadrant
230           if ( i >= (uint32_t)(4 * totalNodes) / 10 )
231             {
232               containerC.Add (c.Get (i));
233             }
234         }
235       if ( (i % gridSize) >= (gridSize / 2 - 1))
236         {
237           //lower right quadrant
238           if ( i < totalNodes / 2 )
239             {
240               containerB.Add (c.Get (i));
241             }
242 
243           //upper right quadrant
244           if ( i >= (uint32_t)(4 * totalNodes) / 10  )
245             {
246               containerD.Add (c.Get (i));
247             }
248         }
249     }
250 }
251 
252 /**
253  * Generate 1-hop and 2-hop neighbors of a node in grid topology
254  *
255  */
256 NodeContainer
GenerateNeighbors(NodeContainer c,uint32_t senderId)257 Experiment::GenerateNeighbors (NodeContainer c, uint32_t senderId)
258 {
259   NodeContainer nc;
260   uint32_t limit = senderId + 2;
261   for (uint32_t i = senderId - 2; i <= limit; i++)
262     {
263       //must ensure the boundaries for other topologies
264       nc.Add (c.Get (i));
265       nc.Add (c.Get (i + 10));
266       nc.Add (c.Get (i + 20));
267       nc.Add (c.Get (i - 10));
268       nc.Add (c.Get (i - 20));
269     }
270   return nc;
271 }
272 
273 /**
274  * Sources and destinations are randomly selected such that a node
275  * may be the source for multiple destinations and a node maybe a destination
276  * for multiple sources.
277  */
278 void
SelectSrcDest(NodeContainer c)279 Experiment::SelectSrcDest (NodeContainer c)
280 {
281   uint32_t totalNodes = c.GetN ();
282   Ptr<UniformRandomVariable> uvSrc = CreateObject<UniformRandomVariable> ();
283   uvSrc->SetAttribute ("Min", DoubleValue (0));
284   uvSrc->SetAttribute ("Max", DoubleValue (totalNodes / 2 - 1));
285   Ptr<UniformRandomVariable> uvDest = CreateObject<UniformRandomVariable> ();
286   uvDest->SetAttribute ("Min", DoubleValue (totalNodes / 2));
287   uvDest->SetAttribute ("Max", DoubleValue (totalNodes));
288 
289   for (uint32_t i = 0; i < totalNodes / 3; i++)
290     {
291       ApplicationSetup (c.Get (uvSrc->GetInteger ()), c.Get (uvDest->GetInteger ()),  0, totalTime);
292     }
293 }
294 
295 /**
296  *
297  * A sender node will  set up a flow to each of the its neighbors
298  * in its quadrant randomly.  All the flows are exponentially distributed
299  *
300  */
301 void
SendMultiDestinations(Ptr<Node> sender,NodeContainer c)302 Experiment::SendMultiDestinations (Ptr<Node> sender, NodeContainer c)
303 {
304 
305   // UniformRandomVariable params: (Xrange, Yrange)
306   Ptr<UniformRandomVariable> uv = CreateObject<UniformRandomVariable> ();
307   uv->SetAttribute ("Min", DoubleValue (0));
308   uv->SetAttribute ("Max", DoubleValue (c.GetN ()));
309 
310   // ExponentialRandomVariable params: (mean, upperbound)
311   Ptr<ExponentialRandomVariable> ev = CreateObject<ExponentialRandomVariable> ();
312   ev->SetAttribute ("Mean", DoubleValue (expMean));
313   ev->SetAttribute ("Bound", DoubleValue (totalTime));
314 
315   double start = 0.0, stop;
316   uint32_t destIndex;
317 
318   for (uint32_t i = 0; i < c.GetN (); i++)
319     {
320       stop = start + ev->GetValue ();
321       NS_LOG_DEBUG ("Start=" << start << " Stop=" << stop);
322 
323       do
324         {
325           destIndex = (uint32_t) uv->GetValue ();
326         }
327       while ( (c.Get (destIndex))->GetId () == sender->GetId ());
328 
329       ApplicationSetup (sender, c.Get (destIndex),  start, stop);
330 
331       start = stop;
332 
333       if (start > totalTime)
334         {
335           break;
336         }
337     }
338 }
339 
340 static inline Vector
GetPosition(Ptr<Node> node)341 GetPosition (Ptr<Node> node)
342 {
343   Ptr<MobilityModel> mobility = node->GetObject<MobilityModel> ();
344   return mobility->GetPosition ();
345 }
346 
347 static inline std::string
PrintPosition(Ptr<Node> client,Ptr<Node> server)348 PrintPosition (Ptr<Node> client, Ptr<Node> server)
349 {
350   Vector serverPos = GetPosition (server);
351   Vector clientPos = GetPosition (client);
352 
353   Ptr<Ipv4> ipv4Server = server->GetObject<Ipv4> ();
354   Ptr<Ipv4> ipv4Client = client->GetObject<Ipv4> ();
355 
356   Ipv4InterfaceAddress iaddrServer = ipv4Server->GetAddress (1,0);
357   Ipv4InterfaceAddress iaddrClient = ipv4Client->GetAddress (1,0);
358 
359   Ipv4Address ipv4AddrServer = iaddrServer.GetLocal ();
360   Ipv4Address ipv4AddrClient = iaddrClient.GetLocal ();
361 
362   std::ostringstream oss;
363   oss << "Set up Server Device " <<  (server->GetDevice (0))->GetAddress ()
364       << " with ip " << ipv4AddrServer
365       << " position (" << serverPos.x << "," << serverPos.y << "," << serverPos.z << ")";
366 
367   oss << "Set up Client Device " <<  (client->GetDevice (0))->GetAddress ()
368       << " with ip " << ipv4AddrClient
369       << " position (" << clientPos.x << "," << clientPos.y << "," << clientPos.z << ")"
370       << "\n";
371   return oss.str ();
372 }
373 
374 void
ApplicationSetup(Ptr<Node> client,Ptr<Node> server,double start,double stop)375 Experiment::ApplicationSetup (Ptr<Node> client, Ptr<Node> server, double start, double stop)
376 {
377   Ptr<Ipv4> ipv4Server = server->GetObject<Ipv4> ();
378 
379   Ipv4InterfaceAddress iaddrServer = ipv4Server->GetAddress (1,0);
380   Ipv4Address ipv4AddrServer = iaddrServer.GetLocal ();
381 
382   NS_LOG_DEBUG (PrintPosition (client, server));
383 
384   // Equipping the source  node with OnOff Application used for sending
385   OnOffHelper onoff ("ns3::UdpSocketFactory", Address (InetSocketAddress (Ipv4Address ("10.0.0.1"), port)));
386   onoff.SetConstantRate (DataRate (60000000));
387   onoff.SetAttribute ("PacketSize", UintegerValue (packetSize));
388   onoff.SetAttribute ("Remote", AddressValue (InetSocketAddress (ipv4AddrServer, port)));
389 
390   ApplicationContainer apps = onoff.Install (client);
391   apps.Start (Seconds (start));
392   apps.Stop (Seconds (stop));
393 
394   Ptr<Socket> sink = SetupPacketReceive (server);
395 
396 }
397 
398 Gnuplot2dDataset
Run(const WifiHelper & wifi,const YansWifiPhyHelper & wifiPhy,const WifiMacHelper & wifiMac,const YansWifiChannelHelper & wifiChannel,const MobilityHelper & mobility)399 Experiment::Run (const WifiHelper &wifi, const YansWifiPhyHelper &wifiPhy,
400                  const WifiMacHelper &wifiMac, const YansWifiChannelHelper &wifiChannel, const MobilityHelper &mobility)
401 {
402 
403 
404   uint32_t nodeSize = gridSize * gridSize;
405   NodeContainer c;
406   c.Create (nodeSize);
407 
408   YansWifiPhyHelper phy = wifiPhy;
409   phy.SetChannel (wifiChannel.Create ());
410 
411   WifiMacHelper mac = wifiMac;
412   NetDeviceContainer devices = wifi.Install (phy, mac, c);
413 
414 
415   OlsrHelper olsr;
416   Ipv4StaticRoutingHelper staticRouting;
417 
418   Ipv4ListRoutingHelper list;
419 
420   if (enableRouting)
421     {
422       list.Add (staticRouting, 0);
423       list.Add (olsr, 10);
424     }
425 
426   InternetStackHelper internet;
427 
428   if (enableRouting)
429     {
430       internet.SetRoutingHelper (list);  // has effect on the next Install ()
431     }
432   internet.Install (c);
433 
434 
435   Ipv4AddressHelper address;
436   address.SetBase ("10.0.0.0", "255.255.255.0");
437 
438   Ipv4InterfaceContainer ipInterfaces;
439   ipInterfaces = address.Assign (devices);
440 
441   MobilityHelper mobil = mobility;
442   mobil.SetPositionAllocator ("ns3::GridPositionAllocator",
443                               "MinX", DoubleValue (0.0),
444                               "MinY", DoubleValue (0.0),
445                               "DeltaX", DoubleValue (nodeDistance),
446                               "DeltaY", DoubleValue (nodeDistance),
447                               "GridWidth", UintegerValue (gridSize),
448                               "LayoutType", StringValue ("RowFirst"));
449 
450   mobil.SetMobilityModel ("ns3::ConstantPositionMobilityModel");
451 
452   if (enableMobility && enableRouting)
453     {
454       //Rectangle (xMin, xMax, yMin, yMax)
455       mobil.SetMobilityModel ("ns3::RandomDirection2dMobilityModel",
456                               "Bounds", RectangleValue (Rectangle (0, 500, 0, 500)),
457                               "Speed", StringValue ("ns3::ConstantRandomVariable[Constant=10]"),
458                               "Pause", StringValue ("ns3::ConstantRandomVariable[Constant=0.2]"));
459     }
460   mobil.Install (c);
461 
462   if ( scenario == 1 && enableRouting)
463     {
464       SelectSrcDest (c);
465     }
466   else if ( scenario == 2)
467     {
468       //All flows begin at the same time
469       for (uint32_t i = 0; i < nodeSize - 1; i = i + 2)
470         {
471           ApplicationSetup (c.Get (i), c.Get (i + 1),  0, totalTime);
472         }
473     }
474   else if ( scenario == 3)
475     {
476       AssignNeighbors (c);
477       //Note: these senders are hand-picked in order to ensure good coverage
478       //for 10x10 grid, basically one sender for each quadrant
479       //you might have to change these values for other grids
480       NS_LOG_DEBUG (">>>>>>>>>region A<<<<<<<<<");
481       SendMultiDestinations (c.Get (22), containerA);
482 
483       NS_LOG_DEBUG (">>>>>>>>>region B<<<<<<<<<");
484       SendMultiDestinations (c.Get (26), containerB);
485 
486       NS_LOG_DEBUG (">>>>>>>>>region C<<<<<<<<<");
487       SendMultiDestinations (c.Get (72), containerC);
488 
489       NS_LOG_DEBUG (">>>>>>>>>region D<<<<<<<<<");
490       SendMultiDestinations (c.Get (76), containerD);
491     }
492   else if ( scenario == 4)
493     {
494       //GenerateNeighbors(NodeContainer, uint32_t sender)
495       //Note: these senders are hand-picked in order to ensure good coverage
496       //you might have to change these values for other grids
497       NodeContainer c1, c2, c3, c4, c5, c6, c7, c8, c9;
498 
499       c1 = GenerateNeighbors (c, 22);
500       c2 = GenerateNeighbors (c, 24);
501       c3 = GenerateNeighbors (c, 26);
502       c4 = GenerateNeighbors (c, 42);
503       c5 = GenerateNeighbors (c, 44);
504       c6 = GenerateNeighbors (c, 46);
505       c7 = GenerateNeighbors (c, 62);
506       c8 = GenerateNeighbors (c, 64);
507       c9 = GenerateNeighbors (c, 66);
508 
509       SendMultiDestinations (c.Get (22), c1);
510       SendMultiDestinations (c.Get (24), c2);
511       SendMultiDestinations (c.Get (26), c3);
512       SendMultiDestinations (c.Get (42), c4);
513       SendMultiDestinations (c.Get (44), c5);
514       SendMultiDestinations (c.Get (46), c6);
515       SendMultiDestinations (c.Get (62), c7);
516       SendMultiDestinations (c.Get (64), c8);
517       SendMultiDestinations (c.Get (66), c9);
518     }
519 
520   CheckThroughput ();
521 
522   if (enablePcap)
523     {
524       phy.SetPcapDataLinkType (WifiPhyHelper::DLT_IEEE802_11_RADIO);
525       phy.EnablePcapAll (GetOutputFileName ());
526     }
527 
528   if (enableTracing)
529     {
530       AsciiTraceHelper ascii;
531       phy.EnableAsciiAll (ascii.CreateFileStream (GetOutputFileName () + ".tr"));
532     }
533 
534   FlowMonitorHelper flowmonHelper;
535 
536   if (enableFlowMon)
537     {
538       flowmonHelper.InstallAll ();
539     }
540 
541   Simulator::Stop (Seconds (totalTime));
542   Simulator::Run ();
543 
544   if (enableFlowMon)
545     {
546       flowmonHelper.SerializeToXmlFile ((GetOutputFileName () + ".flomon"), false, false);
547     }
548 
549   Simulator::Destroy ();
550 
551   return m_output;
552 }
553 
554 bool
CommandSetup(int argc,char ** argv)555 Experiment::CommandSetup (int argc, char **argv)
556 {
557   // for commandline input
558   CommandLine cmd (__FILE__);
559   cmd.AddValue ("packetSize", "packet size", packetSize);
560   cmd.AddValue ("totalTime", "simulation time", totalTime);
561   // according to totalTime, select an appropriate samplingPeriod automatically.
562   if (totalTime < 1.0)
563     {
564       samplingPeriod = 0.1;
565     }
566   else
567     {
568       samplingPeriod = 1.0;
569     }
570   // or user selects a samplingPeriod.
571   cmd.AddValue ("samplingPeriod", "sampling period", samplingPeriod);
572   cmd.AddValue ("rtsThreshold", "rts threshold", rtsThreshold);
573   cmd.AddValue ("rateManager", "type of rate", rateManager);
574   cmd.AddValue ("outputFileName", "output filename", outputFileName);
575   cmd.AddValue ("enableRouting", "enable Routing", enableRouting);
576   cmd.AddValue ("enableMobility", "enable Mobility", enableMobility);
577   cmd.AddValue ("scenario", "scenario ", scenario);
578 
579   cmd.Parse (argc, argv);
580   return true;
581 }
582 
main(int argc,char * argv[])583 int main (int argc, char *argv[])
584 {
585 
586   Experiment experiment;
587   experiment = Experiment ("multirate");
588 
589   //for commandline input
590   experiment.CommandSetup (argc, argv);
591 
592   std::ofstream outfile ((experiment.GetOutputFileName () + ".plt").c_str ());
593 
594   MobilityHelper mobility;
595   Gnuplot gnuplot;
596   Gnuplot2dDataset dataset;
597 
598   WifiHelper wifi;
599   WifiMacHelper wifiMac;
600   YansWifiPhyHelper wifiPhy;
601   YansWifiChannelHelper wifiChannel = YansWifiChannelHelper::Default ();
602 
603   wifiMac.SetType ("ns3::AdhocWifiMac",
604                    "Ssid", StringValue ("Testbed"));
605   wifi.SetStandard (WIFI_STANDARD_80211a);
606   wifi.SetRemoteStationManager (experiment.GetRateManager ());
607 
608   NS_LOG_INFO ("Scenario: " << experiment.GetScenario ());
609   NS_LOG_INFO ("Rts Threshold: " << experiment.GetRtsThreshold ());
610   NS_LOG_INFO ("Name:  " << experiment.GetOutputFileName ());
611   NS_LOG_INFO ("Rate:  " << experiment.GetRateManager ());
612   NS_LOG_INFO ("Routing: " << experiment.IsRouting ());
613   NS_LOG_INFO ("Mobility: " << experiment.IsMobility ());
614 
615   dataset = experiment.Run (wifi, wifiPhy, wifiMac, wifiChannel, mobility);
616 
617   gnuplot.AddDataset (dataset);
618   gnuplot.GenerateOutput (outfile);
619 
620   return 0;
621 }
622