1 /* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2015 SEBASTIEN DERONNE
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation;
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17  *
18  * Author: Sebastien Deronne <sebastien.deronne@gmail.com>
19  */
20 
21 #include "ns3/command-line.h"
22 #include "ns3/config.h"
23 #include "ns3/uinteger.h"
24 #include "ns3/boolean.h"
25 #include "ns3/double.h"
26 #include "ns3/string.h"
27 #include "ns3/log.h"
28 #include "ns3/yans-wifi-helper.h"
29 #include "ns3/ssid.h"
30 #include "ns3/mobility-helper.h"
31 #include "ns3/internet-stack-helper.h"
32 #include "ns3/ipv4-address-helper.h"
33 #include "ns3/udp-client-server-helper.h"
34 #include "ns3/packet-sink-helper.h"
35 #include "ns3/on-off-helper.h"
36 #include "ns3/ipv4-global-routing-helper.h"
37 #include "ns3/packet-sink.h"
38 #include "ns3/yans-wifi-channel.h"
39 
40 // This is a simple example in order to show how to configure an IEEE 802.11ac Wi-Fi network.
41 //
42 // It outputs the UDP or TCP goodput for every VHT MCS value, which depends on the MCS value (0 to 9, where 9 is
43 // forbidden when the channel width is 20 MHz), the channel width (20, 40, 80 or 160 MHz) and the guard interval (long
44 // or short). The PHY bitrate is constant over all the simulation run. The user can also specify the distance between
45 // the access point and the station: the larger the distance the smaller the goodput.
46 //
47 // The simulation assumes a single station in an infrastructure network:
48 //
49 //  STA     AP
50 //    *     *
51 //    |     |
52 //   n1     n2
53 //
54 //Packets in this simulation belong to BestEffort Access Class (AC_BE).
55 
56 using namespace ns3;
57 
58 NS_LOG_COMPONENT_DEFINE ("vht-wifi-network");
59 
main(int argc,char * argv[])60 int main (int argc, char *argv[])
61 {
62   bool udp = true;
63   bool useRts = false;
64   double simulationTime = 10; //seconds
65   double distance = 1.0; //meters
66   int mcs = -1; // -1 indicates an unset value
67   double minExpectedThroughput = 0;
68   double maxExpectedThroughput = 0;
69 
70   CommandLine cmd (__FILE__);
71   cmd.AddValue ("distance", "Distance in meters between the station and the access point", distance);
72   cmd.AddValue ("simulationTime", "Simulation time in seconds", simulationTime);
73   cmd.AddValue ("udp", "UDP if set to 1, TCP otherwise", udp);
74   cmd.AddValue ("useRts", "Enable/disable RTS/CTS", useRts);
75   cmd.AddValue ("mcs", "if set, limit testing to a specific MCS (0-9)", mcs);
76   cmd.AddValue ("minExpectedThroughput", "if set, simulation fails if the lowest throughput is below this value", minExpectedThroughput);
77   cmd.AddValue ("maxExpectedThroughput", "if set, simulation fails if the highest throughput is above this value", maxExpectedThroughput);
78   cmd.Parse (argc,argv);
79 
80   if (useRts)
81     {
82       Config::SetDefault ("ns3::WifiRemoteStationManager::RtsCtsThreshold", StringValue ("0"));
83     }
84 
85   double prevThroughput [8];
86   for (uint32_t l = 0; l < 8; l++)
87     {
88       prevThroughput[l] = 0;
89     }
90   std::cout << "MCS value" << "\t\t" << "Channel width" << "\t\t" << "short GI" << "\t\t" << "Throughput" << '\n';
91   int minMcs = 0;
92   int maxMcs = 9;
93   if (mcs >= 0 && mcs <= 9)
94     {
95       minMcs = mcs;
96       maxMcs = mcs;
97     }
98   for (int mcs = minMcs; mcs <= maxMcs; mcs++)
99     {
100       uint8_t index = 0;
101       double previous = 0;
102       for (int channelWidth = 20; channelWidth <= 160; )
103         {
104           if (mcs == 9 && channelWidth == 20)
105             {
106               channelWidth *= 2;
107               continue;
108             }
109           for (int sgi = 0; sgi < 2; sgi++)
110             {
111               uint32_t payloadSize; //1500 byte IP packet
112               if (udp)
113                 {
114                   payloadSize = 1472; //bytes
115                 }
116               else
117                 {
118                   payloadSize = 1448; //bytes
119                   Config::SetDefault ("ns3::TcpSocket::SegmentSize", UintegerValue (payloadSize));
120                 }
121 
122               NodeContainer wifiStaNode;
123               wifiStaNode.Create (1);
124               NodeContainer wifiApNode;
125               wifiApNode.Create (1);
126 
127               YansWifiChannelHelper channel = YansWifiChannelHelper::Default ();
128               YansWifiPhyHelper phy;
129               phy.SetChannel (channel.Create ());
130 
131               WifiHelper wifi;
132               wifi.SetStandard (WIFI_STANDARD_80211ac);
133               WifiMacHelper mac;
134 
135               std::ostringstream oss;
136               oss << "VhtMcs" << mcs;
137               wifi.SetRemoteStationManager ("ns3::ConstantRateWifiManager","DataMode", StringValue (oss.str ()),
138                                             "ControlMode", StringValue (oss.str ()));
139 
140               Ssid ssid = Ssid ("ns3-80211ac");
141 
142               mac.SetType ("ns3::StaWifiMac",
143                            "Ssid", SsidValue (ssid));
144               phy.Set ("ChannelWidth", UintegerValue (channelWidth));
145 
146               NetDeviceContainer staDevice;
147               staDevice = wifi.Install (phy, mac, wifiStaNode);
148 
149               mac.SetType ("ns3::ApWifiMac",
150                            "EnableBeaconJitter", BooleanValue (false),
151                            "Ssid", SsidValue (ssid));
152               phy.Set ("ChannelWidth", UintegerValue (channelWidth));
153 
154               NetDeviceContainer apDevice;
155               apDevice = wifi.Install (phy, mac, wifiApNode);
156 
157               // Set guard interval
158               Config::Set ("/NodeList/*/DeviceList/*/$ns3::WifiNetDevice/HtConfiguration/ShortGuardIntervalSupported", BooleanValue (sgi));
159 
160               // mobility.
161               MobilityHelper mobility;
162               Ptr<ListPositionAllocator> positionAlloc = CreateObject<ListPositionAllocator> ();
163 
164               positionAlloc->Add (Vector (0.0, 0.0, 0.0));
165               positionAlloc->Add (Vector (distance, 0.0, 0.0));
166               mobility.SetPositionAllocator (positionAlloc);
167 
168               mobility.SetMobilityModel ("ns3::ConstantPositionMobilityModel");
169 
170               mobility.Install (wifiApNode);
171               mobility.Install (wifiStaNode);
172 
173               /* Internet stack*/
174               InternetStackHelper stack;
175               stack.Install (wifiApNode);
176               stack.Install (wifiStaNode);
177 
178               Ipv4AddressHelper address;
179               address.SetBase ("192.168.1.0", "255.255.255.0");
180               Ipv4InterfaceContainer staNodeInterface;
181               Ipv4InterfaceContainer apNodeInterface;
182 
183               staNodeInterface = address.Assign (staDevice);
184               apNodeInterface = address.Assign (apDevice);
185 
186               /* Setting applications */
187               ApplicationContainer serverApp;
188               if (udp)
189                 {
190                   //UDP flow
191                   uint16_t port = 9;
192                   UdpServerHelper server (port);
193                   serverApp = server.Install (wifiStaNode.Get (0));
194                   serverApp.Start (Seconds (0.0));
195                   serverApp.Stop (Seconds (simulationTime + 1));
196 
197                   UdpClientHelper client (staNodeInterface.GetAddress (0), port);
198                   client.SetAttribute ("MaxPackets", UintegerValue (4294967295u));
199                   client.SetAttribute ("Interval", TimeValue (Time ("0.00002"))); //packets/s
200                   client.SetAttribute ("PacketSize", UintegerValue (payloadSize));
201                   ApplicationContainer clientApp = client.Install (wifiApNode.Get (0));
202                   clientApp.Start (Seconds (1.0));
203                   clientApp.Stop (Seconds (simulationTime + 1));
204                 }
205               else
206                 {
207                   //TCP flow
208                   uint16_t port = 50000;
209                   Address localAddress (InetSocketAddress (Ipv4Address::GetAny (), port));
210                   PacketSinkHelper packetSinkHelper ("ns3::TcpSocketFactory", localAddress);
211                   serverApp = packetSinkHelper.Install (wifiStaNode.Get (0));
212                   serverApp.Start (Seconds (0.0));
213                   serverApp.Stop (Seconds (simulationTime + 1));
214 
215                   OnOffHelper onoff ("ns3::TcpSocketFactory", Ipv4Address::GetAny ());
216                   onoff.SetAttribute ("OnTime",  StringValue ("ns3::ConstantRandomVariable[Constant=1]"));
217                   onoff.SetAttribute ("OffTime", StringValue ("ns3::ConstantRandomVariable[Constant=0]"));
218                   onoff.SetAttribute ("PacketSize", UintegerValue (payloadSize));
219                   onoff.SetAttribute ("DataRate", DataRateValue (1000000000)); //bit/s
220                   AddressValue remoteAddress (InetSocketAddress (staNodeInterface.GetAddress (0), port));
221                   onoff.SetAttribute ("Remote", remoteAddress);
222                   ApplicationContainer clientApp = onoff.Install (wifiApNode.Get (0));
223                   clientApp.Start (Seconds (1.0));
224                   clientApp.Stop (Seconds (simulationTime + 1));
225                 }
226 
227               Ipv4GlobalRoutingHelper::PopulateRoutingTables ();
228 
229               Simulator::Stop (Seconds (simulationTime + 1));
230               Simulator::Run ();
231 
232               uint64_t rxBytes = 0;
233               if (udp)
234                 {
235                   rxBytes = payloadSize * DynamicCast<UdpServer> (serverApp.Get (0))->GetReceived ();
236                 }
237               else
238                 {
239                   rxBytes = DynamicCast<PacketSink> (serverApp.Get (0))->GetTotalRx ();
240                 }
241               double throughput = (rxBytes * 8) / (simulationTime * 1000000.0); //Mbit/s
242 
243               Simulator::Destroy ();
244 
245               std::cout << mcs << "\t\t\t" << channelWidth << " MHz\t\t\t" << sgi << "\t\t\t" << throughput << " Mbit/s" << std::endl;
246 
247               //test first element
248               if (mcs == 0 && channelWidth == 20 && sgi == 0)
249                 {
250                   if (throughput < minExpectedThroughput)
251                     {
252                       NS_LOG_ERROR ("Obtained throughput " << throughput << " is not expected!");
253                       exit (1);
254                     }
255                 }
256               //test last element
257               if (mcs == 9 && channelWidth == 160 && sgi == 1)
258                 {
259                   if (maxExpectedThroughput > 0 && throughput > maxExpectedThroughput)
260                     {
261                       NS_LOG_ERROR ("Obtained throughput " << throughput << " is not expected!");
262                       exit (1);
263                     }
264                 }
265               //test previous throughput is smaller (for the same mcs)
266               if (throughput > previous)
267                 {
268                   previous = throughput;
269                 }
270               else
271                 {
272                   NS_LOG_ERROR ("Obtained throughput " << throughput << " is not expected!");
273                   exit (1);
274                 }
275               //test previous throughput is smaller (for the same channel width and GI)
276               if (throughput > prevThroughput [index])
277                 {
278                   prevThroughput [index] = throughput;
279                 }
280               else
281                 {
282                   NS_LOG_ERROR ("Obtained throughput " << throughput << " is not expected!");
283                   exit (1);
284                 }
285               index++;
286             }
287           channelWidth *= 2;
288         }
289     }
290   return 0;
291 }
292