/* * Copyright (c) 2016 Sébastien Deronne * * 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 * * Author: Sébastien Deronne */ #include "ns3/command-line.h" #include "ns3/config.h" #include "ns3/ht-configuration.h" #include "ns3/internet-stack-helper.h" #include "ns3/ipv4-address-helper.h" #include "ns3/log.h" #include "ns3/mobility-helper.h" #include "ns3/on-off-helper.h" #include "ns3/packet-sink-helper.h" #include "ns3/packet-sink.h" #include "ns3/pointer.h" #include "ns3/qos-txop.h" #include "ns3/ssid.h" #include "ns3/string.h" #include "ns3/udp-client-server-helper.h" #include "ns3/wifi-mac.h" #include "ns3/wifi-net-device.h" #include "ns3/yans-wifi-channel.h" #include "ns3/yans-wifi-helper.h" // This example shows how to configure mixed networks (i.e. mixed b/g and HT/non-HT) and how are // performance in several scenarios. // // The example compares first g only and mixed b/g cases with various configurations depending on // the following parameters: // - protection mode that is configured on the AP; // - whether short PPDU format is supported by the 802.11b station; // - whether short slot time is supported by both the 802.11g station and the AP. // // The example then compares HT only and mixed HT/non-HT cases. // // The output results show that the presence of an 802.11b station strongly affects 802.11g // performance. Protection mechanisms ensure that the NAV value of 802.11b stations is set correctly // in case of 802.11g transmissions. In practice, those protection mechanism add a lot of overhead, // resulting in reduced performance. CTS-To-Self introduces less overhead than Rts-Cts, but is not // heard by hidden stations (and is thus generally only recommended as a protection mechanism for // access points). Since short slot time is disabled once an 802.11b station enters the network, // benefits from short slot time are only observed in a g only configuration. // // The user can also select the payload size and can choose either an UDP or a TCP connection. // Example: ./ns3 run "wifi-mixed-network --isUdp=1" using namespace ns3; NS_LOG_COMPONENT_DEFINE("MixedNetwork"); /** Parameters */ struct Parameters { std::string testName; //!< Test name bool enableErpProtection; //!< True to enable ERP protection std::string erpProtectionMode; //!< ERP protection mode bool enableShortSlotTime; //!< True to enable short slot time bool enableShortPhyPreamble; //!< True to enable short PHY preamble WifiStandard apType; //!< Wifi standard for AP uint32_t nWifiB; //!< Number of 802.11b stations bool bHasTraffic; //!< True if 802.11b stations generate traffic uint32_t nWifiG; //!< Number of 802.11g stations bool gHasTraffic; //!< True if 802.11g stations generate traffic uint32_t nWifiN; //!< Number of 802.11n stations bool nHasTraffic; //!< True if 802.11n stations generate traffic bool isUdp; //!< True to generate UDP traffic uint32_t payloadSize; //!< Payload size in bytes double simulationTime; //!< Simulation time in seconds }; class Experiment { public: Experiment(); /** * Run an experiment with the given parameters * \param params the given parameters * \return the throughput */ double Run(Parameters params); }; Experiment::Experiment() { } double Experiment::Run(Parameters params) { std::string apTypeString; if (params.apType == WIFI_STANDARD_80211g) { apTypeString = "WIFI_STANDARD_80211g"; } else if (params.apType == WIFI_STANDARD_80211n) { apTypeString = "WIFI_STANDARD_80211n_2_4GHZ"; } std::cout << "Run: " << params.testName << "\n\t enableErpProtection=" << params.enableErpProtection << "\n\t erpProtectionMode=" << params.erpProtectionMode << "\n\t enableShortSlotTime=" << params.enableShortSlotTime << "\n\t enableShortPhyPreamble=" << params.enableShortPhyPreamble << "\n\t apType=" << apTypeString << "\n\t nWifiB=" << params.nWifiB << "\n\t bHasTraffic=" << params.bHasTraffic << "\n\t nWifiG=" << params.nWifiG << "\n\t gHasTraffic=" << params.gHasTraffic << "\n\t nWifiN=" << params.nWifiN << "\n\t nHasTraffic=" << params.nHasTraffic << std::endl; Config::SetDefault("ns3::WifiRemoteStationManager::ErpProtectionMode", StringValue(params.erpProtectionMode)); double throughput = 0; uint32_t nWifiB = params.nWifiB; uint32_t nWifiG = params.nWifiG; uint32_t nWifiN = params.nWifiN; double simulationTime = params.simulationTime; uint32_t payloadSize = params.payloadSize; NodeContainer wifiBStaNodes; wifiBStaNodes.Create(nWifiB); NodeContainer wifiGStaNodes; wifiGStaNodes.Create(nWifiG); NodeContainer wifiNStaNodes; wifiNStaNodes.Create(nWifiN); NodeContainer wifiApNode; wifiApNode.Create(1); YansWifiChannelHelper channel = YansWifiChannelHelper::Default(); channel.AddPropagationLoss("ns3::RangePropagationLossModel"); YansWifiPhyHelper phy; phy.SetChannel(channel.Create()); WifiHelper wifi; wifi.SetRemoteStationManager("ns3::IdealWifiManager"); // 802.11b STA wifi.SetStandard(WIFI_STANDARD_80211b); WifiMacHelper mac; Ssid ssid = Ssid("ns-3-ssid"); mac.SetType("ns3::StaWifiMac", "Ssid", SsidValue(ssid), "ShortSlotTimeSupported", BooleanValue(params.enableShortSlotTime)); // Configure the PHY preamble type: long or short phy.Set("ShortPlcpPreambleSupported", BooleanValue(params.enableShortPhyPreamble)); NetDeviceContainer bStaDevice; bStaDevice = wifi.Install(phy, mac, wifiBStaNodes); // 802.11b/g STA wifi.SetStandard(WIFI_STANDARD_80211g); NetDeviceContainer gStaDevice; gStaDevice = wifi.Install(phy, mac, wifiGStaNodes); // 802.11b/g/n STA wifi.SetStandard(WIFI_STANDARD_80211n); NetDeviceContainer nStaDevice; mac.SetType("ns3::StaWifiMac", "Ssid", SsidValue(ssid), "BE_BlockAckThreshold", UintegerValue(2), "ShortSlotTimeSupported", BooleanValue(params.enableShortSlotTime)); nStaDevice = wifi.Install(phy, mac, wifiNStaNodes); // AP NetDeviceContainer apDevice; wifi.SetStandard(params.apType); mac.SetType("ns3::ApWifiMac", "Ssid", SsidValue(ssid), "EnableBeaconJitter", BooleanValue(false), "BE_BlockAckThreshold", UintegerValue(2), "EnableNonErpProtection", BooleanValue(params.enableErpProtection), "ShortSlotTimeSupported", BooleanValue(params.enableShortSlotTime)); apDevice = wifi.Install(phy, mac, wifiApNode); // Set TXOP limit if (params.apType == WIFI_STANDARD_80211n) { Ptr dev = wifiApNode.Get(0)->GetDevice(0); Ptr wifi_dev = DynamicCast(dev); Ptr wifi_mac = wifi_dev->GetMac(); PointerValue ptr; wifi_mac->GetAttribute("BE_Txop", ptr); Ptr edca = ptr.Get(); edca->SetTxopLimit(MicroSeconds(3008)); } if (nWifiN > 0) { Ptr dev = wifiNStaNodes.Get(0)->GetDevice(0); Ptr wifi_dev = DynamicCast(dev); Ptr wifi_mac = wifi_dev->GetMac(); PointerValue ptr; wifi_mac->GetAttribute("BE_Txop", ptr); Ptr edca = ptr.Get(); edca->SetTxopLimit(MicroSeconds(3008)); } Config::Set("/NodeList/*/DeviceList/*/$ns3::WifiNetDevice/Mac/BE_MaxAmpduSize", UintegerValue(0)); // Disable A-MPDU // Define mobility model MobilityHelper mobility; Ptr positionAlloc = CreateObject(); positionAlloc->Add(Vector(0.0, 0.0, 0.0)); for (uint32_t i = 0; i < nWifiB; i++) { positionAlloc->Add(Vector(5.0, 0.0, 0.0)); } for (uint32_t i = 0; i < nWifiG; i++) { positionAlloc->Add(Vector(0.0, 5.0, 0.0)); } for (uint32_t i = 0; i < nWifiN; i++) { positionAlloc->Add(Vector(0.0, 0.0, 5.0)); } mobility.SetPositionAllocator(positionAlloc); mobility.SetMobilityModel("ns3::ConstantPositionMobilityModel"); mobility.Install(wifiApNode); mobility.Install(wifiBStaNodes); mobility.Install(wifiGStaNodes); mobility.Install(wifiNStaNodes); // Internet stack InternetStackHelper stack; stack.Install(wifiApNode); stack.Install(wifiBStaNodes); stack.Install(wifiGStaNodes); stack.Install(wifiNStaNodes); Ipv4AddressHelper address; address.SetBase("192.168.1.0", "255.255.255.0"); Ipv4InterfaceContainer bStaInterface; bStaInterface = address.Assign(bStaDevice); Ipv4InterfaceContainer gStaInterface; gStaInterface = address.Assign(gStaDevice); Ipv4InterfaceContainer nStaInterface; nStaInterface = address.Assign(nStaDevice); Ipv4InterfaceContainer ApInterface; ApInterface = address.Assign(apDevice); // Setting applications if (params.isUdp) { uint16_t port = 9; UdpServerHelper server(port); ApplicationContainer serverApp = server.Install(wifiApNode); serverApp.Start(Seconds(0.0)); serverApp.Stop(Seconds(simulationTime + 1)); UdpClientHelper client(ApInterface.GetAddress(0), port); client.SetAttribute("MaxPackets", UintegerValue(4294967295U)); client.SetAttribute("Interval", TimeValue(Time("0.0002"))); // packets/s client.SetAttribute("PacketSize", UintegerValue(payloadSize)); ApplicationContainer clientApps; if (params.bHasTraffic) { clientApps.Add(client.Install(wifiBStaNodes)); } if (params.gHasTraffic) { clientApps.Add(client.Install(wifiGStaNodes)); } if (params.nHasTraffic) { clientApps.Add(client.Install(wifiNStaNodes)); } clientApps.Start(Seconds(1.0)); clientApps.Stop(Seconds(simulationTime + 1)); Simulator::Stop(Seconds(simulationTime + 1)); Simulator::Run(); uint64_t totalPacketsThrough = DynamicCast(serverApp.Get(0))->GetReceived(); throughput = totalPacketsThrough * payloadSize * 8 / (simulationTime * 1000000.0); } else { uint16_t port = 50000; Address localAddress(InetSocketAddress(Ipv4Address::GetAny(), port)); PacketSinkHelper packetSinkHelper("ns3::TcpSocketFactory", localAddress); ApplicationContainer serverApp = packetSinkHelper.Install(wifiApNode.Get(0)); serverApp.Start(Seconds(0.0)); serverApp.Stop(Seconds(simulationTime + 1)); OnOffHelper onoff("ns3::TcpSocketFactory", Ipv4Address::GetAny()); onoff.SetAttribute("OnTime", StringValue("ns3::ConstantRandomVariable[Constant=1]")); onoff.SetAttribute("OffTime", StringValue("ns3::ConstantRandomVariable[Constant=0]")); onoff.SetAttribute("PacketSize", UintegerValue(payloadSize)); onoff.SetAttribute("DataRate", DataRateValue(150000000)); // bit/s AddressValue remoteAddress(InetSocketAddress(ApInterface.GetAddress(0), port)); onoff.SetAttribute("Remote", remoteAddress); ApplicationContainer clientApps; if (params.bHasTraffic) { clientApps.Add(onoff.Install(wifiBStaNodes)); } if (params.gHasTraffic) { clientApps.Add(onoff.Install(wifiGStaNodes)); } if (params.nHasTraffic) { clientApps.Add(onoff.Install(wifiNStaNodes)); } clientApps.Start(Seconds(1.0)); clientApps.Stop(Seconds(simulationTime + 1)); Simulator::Stop(Seconds(simulationTime + 1)); Simulator::Run(); uint64_t totalPacketsThrough = DynamicCast(serverApp.Get(0))->GetTotalRx(); throughput += totalPacketsThrough * 8 / (simulationTime * 1000000.0); } Simulator::Destroy(); return throughput; } int main(int argc, char* argv[]) { Parameters params; params.testName = ""; params.enableErpProtection = false; params.erpProtectionMode = "Cts-To-Self"; params.enableShortSlotTime = false; params.enableShortPhyPreamble = false; params.apType = WIFI_STANDARD_80211g; params.nWifiB = 0; params.bHasTraffic = false; params.nWifiG = 1; params.gHasTraffic = true; params.nWifiN = 0; params.nHasTraffic = false; params.isUdp = true; params.payloadSize = 1472; // bytes params.simulationTime = 10; // seconds bool verifyResults = 0; // used for regression CommandLine cmd(__FILE__); cmd.AddValue("payloadSize", "Payload size in bytes", params.payloadSize); cmd.AddValue("simulationTime", "Simulation time in seconds", params.simulationTime); cmd.AddValue("isUdp", "UDP if set to 1, TCP otherwise", params.isUdp); cmd.AddValue("verifyResults", "Enable/disable results verification at the end of the simulation", verifyResults); cmd.Parse(argc, argv); Experiment experiment; double throughput = 0; params.testName = "g only with all g features disabled"; throughput = experiment.Run(params); if (verifyResults && (throughput < 22.5 || throughput > 23.5)) { NS_LOG_ERROR("Obtained throughput " << throughput << " is not in the expected boundaries!"); exit(1); } std::cout << "Throughput: " << throughput << " Mbit/s \n" << std::endl; params.testName = "g only with short slot time enabled"; params.enableErpProtection = false; params.enableShortSlotTime = true; params.enableShortPhyPreamble = false; params.nWifiB = 0; throughput = experiment.Run(params); if (verifyResults && (throughput < 29 || throughput > 30)) { NS_LOG_ERROR("Obtained throughput " << throughput << " is not in the expected boundaries!"); exit(1); } std::cout << "Throughput: " << throughput << " Mbit/s \n" << std::endl; params.testName = "Mixed b/g with all g features disabled"; params.enableErpProtection = false; params.enableShortSlotTime = false; params.enableShortPhyPreamble = false; params.nWifiB = 1; throughput = experiment.Run(params); if (verifyResults && (throughput < 22.5 || throughput > 23.5)) { NS_LOG_ERROR("Obtained throughput " << throughput << " is not in the expected boundaries!"); exit(1); } std::cout << "Throughput: " << throughput << " Mbit/s \n" << std::endl; params.testName = "Mixed b/g with short plcp preamble enabled"; params.enableErpProtection = false; params.enableShortSlotTime = false; params.enableShortPhyPreamble = true; params.nWifiB = 1; throughput = experiment.Run(params); if (verifyResults && (throughput < 22.5 || throughput > 23.5)) { NS_LOG_ERROR("Obtained throughput " << throughput << " is not in the expected boundaries!"); exit(1); } std::cout << "Throughput: " << throughput << " Mbit/s \n" << std::endl; params.testName = "Mixed b/g with short slot time enabled using RTS-CTS protection"; params.enableErpProtection = true; params.erpProtectionMode = "Rts-Cts"; params.enableShortSlotTime = false; params.enableShortPhyPreamble = false; params.nWifiB = 1; throughput = experiment.Run(params); if (verifyResults && (throughput < 19 || throughput > 20)) { NS_LOG_ERROR("Obtained throughput " << throughput << " is not in the expected boundaries!"); exit(1); } std::cout << "Throughput: " << throughput << " Mbit/s \n" << std::endl; params.testName = "Mixed b/g with short plcp preamble enabled using RTS-CTS protection"; params.enableErpProtection = true; params.enableShortSlotTime = false; params.enableShortPhyPreamble = true; params.nWifiB = 1; throughput = experiment.Run(params); if (verifyResults && (throughput < 19 || throughput > 20)) { NS_LOG_ERROR("Obtained throughput " << throughput << " is not in the expected boundaries!"); exit(1); } std::cout << "Throughput: " << throughput << " Mbit/s \n" << std::endl; params.testName = "Mixed b/g with short slot time enabled using CTS-TO-SELF protection"; params.enableErpProtection = true; params.erpProtectionMode = "Cts-To-Self"; params.enableShortSlotTime = false; params.enableShortPhyPreamble = false; params.nWifiB = 1; throughput = experiment.Run(params); if (verifyResults && (throughput < 20.5 || throughput > 21.5)) { NS_LOG_ERROR("Obtained throughput " << throughput << " is not in the expected boundaries!"); exit(1); } std::cout << "Throughput: " << throughput << " Mbit/s \n" << std::endl; params.testName = "Mixed b/g with short plcp preamble enabled using CTS-TO-SELF protection"; params.enableErpProtection = true; params.enableShortSlotTime = false; params.enableShortPhyPreamble = true; params.nWifiB = 1; throughput = experiment.Run(params); if (verifyResults && (throughput < 20.5 || throughput > 21.5)) { NS_LOG_ERROR("Obtained throughput " << throughput << " is not in the expected boundaries!"); exit(1); } std::cout << "Throughput: " << throughput << " Mbit/s \n" << std::endl; params.testName = "HT only"; params.enableErpProtection = false; params.enableShortSlotTime = false; params.enableShortPhyPreamble = false; params.apType = WIFI_STANDARD_80211n; params.nWifiB = 0; params.bHasTraffic = false; params.nWifiG = 0; params.gHasTraffic = false; params.nWifiN = 1; params.nHasTraffic = true; throughput = experiment.Run(params); if (verifyResults && (throughput < 44 || throughput > 45)) { NS_LOG_ERROR("Obtained throughput " << throughput << " is not in the expected boundaries!"); exit(1); } std::cout << "Throughput: " << throughput << " Mbit/s \n" << std::endl; params.testName = "Mixed HT/non-HT"; params.enableErpProtection = false; params.enableShortSlotTime = false; params.enableShortPhyPreamble = false; params.apType = WIFI_STANDARD_80211n; params.nWifiB = 0; params.bHasTraffic = false; params.nWifiG = 1; params.gHasTraffic = false; params.nWifiN = 1; params.nHasTraffic = true; throughput = experiment.Run(params); if (verifyResults && (throughput < 44 || throughput > 45)) { NS_LOG_ERROR("Obtained throughput " << throughput << " is not in the expected boundaries!"); exit(1); } std::cout << "Throughput: " << throughput << " Mbit/s \n" << std::endl; return 0; }