|
| 1 | +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ |
| 2 | +/* |
| 3 | + * Copyright (c) 2015 Universita' degli Studi di Napoli Federico II |
| 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 | + * Authors: Pasquale Imputato <p.imputato@gmail.com> |
| 19 | + * Stefano Avallone <stefano.avallone@unina.it> |
| 20 | + */ |
| 21 | + |
| 22 | +// This example serves as benchmark test for all the queue discs (with BQL enabled or not) |
| 23 | +// |
| 24 | +// Network topology |
| 25 | +// |
| 26 | +// 192.168.1.0 192.168.2.0 |
| 27 | +// n1 ------------------------------------ n2 ----------------------------------- n3 |
| 28 | +// point-to-point (access link) point-to-point (bottleneck link) |
| 29 | +// 100 Mbps, 0.1 ms bottleneckBandwidth [10 Mbps], bottleneckDelay [5 ms] |
| 30 | +// qdiscs PfifoFast with capacity qdiscs bottleneckQueueDiscType in {PfifoFast, ARED, CoDel} [PfifoFast] |
| 31 | +// of 1000 packets with capacity of bottleneckQueueDiscSize packets [1000] |
| 32 | +// NetDevices queues with size of 100 packets NetDevices queues with size of bottleneckNetdevicesQueueSize packets [100] |
| 33 | +// without BQL bottleneckBql BQL [false] |
| 34 | +// *** fixed configuration *** |
| 35 | +// |
| 36 | +// The output will consist of a number of ping Rtt such as: |
| 37 | +// |
| 38 | +// /NodeList/0/ApplicationList/8/$ns3::V4Ping/Rtt=10 ms |
| 39 | +// /NodeList/0/ApplicationList/8/$ns3::V4Ping/Rtt=111 ms |
| 40 | +// /NodeList/0/ApplicationList/8/$ns3::V4Ping/Rtt=109 ms |
| 41 | +// /NodeList/0/ApplicationList/8/$ns3::V4Ping/Rtt=109 ms |
| 42 | +// /NodeList/0/ApplicationList/8/$ns3::V4Ping/Rtt=111 ms |
| 43 | +// /NodeList/0/ApplicationList/8/$ns3::V4Ping/Rtt=107 ms |
| 44 | +// /NodeList/0/ApplicationList/8/$ns3::V4Ping/Rtt=111 ms |
| 45 | +// |
| 46 | +// The file output will consist of a trace file with bytes in queue and of a trace file for limits |
| 47 | +// (when BQL is enabled) both for bottleneck NetDevice on n2, two files with upload an download |
| 48 | +// goodput for RRUL-like flows configuration, and a file with flow monitor stats. |
| 49 | +// |
| 50 | +// If you decrease the size of the bottleneckNetdevicesQueueSize from 100 to 50, one can |
| 51 | +// observe that the ping Rtt decreases. A further decrease can be observed when enable bottleneckBql |
| 52 | +// (regardless of the bottleneckNetdevicesQueueSize). |
| 53 | +// Also, you can evaluate the effect combined of the variation of bottleneckQueueDiscType and of |
| 54 | +// the bottleneckNetdevicesQueueSize (with or without BQL). |
| 55 | + |
| 56 | +#include "ns3/core-module.h" |
| 57 | +#include "ns3/network-module.h" |
| 58 | +#include "ns3/internet-module.h" |
| 59 | +#include "ns3/point-to-point-module.h" |
| 60 | +#include "ns3/applications-module.h" |
| 61 | +#include "ns3/internet-apps-module.h" |
| 62 | +#include "ns3/traffic-control-module.h" |
| 63 | +#include "ns3/flow-monitor-module.h" |
| 64 | + |
| 65 | +using namespace ns3; |
| 66 | + |
| 67 | +NS_LOG_COMPONENT_DEFINE ("BenchmarkQueueDiscs"); |
| 68 | + |
| 69 | +void |
| 70 | +LimitsTrace (Ptr<OutputStreamWrapper> stream, uint32_t oldVal, uint32_t newVal) |
| 71 | +{ |
| 72 | + *stream->GetStream () << Simulator::Now ().GetSeconds () << " " << newVal << std::endl; |
| 73 | +} |
| 74 | + |
| 75 | +void |
| 76 | +BytesInQueueTrace (Ptr<OutputStreamWrapper> stream, uint32_t oldVal, uint32_t newVal) |
| 77 | +{ |
| 78 | + *stream->GetStream () << Simulator::Now ().GetSeconds () << " " << newVal << std::endl; |
| 79 | +} |
| 80 | + |
| 81 | +static void |
| 82 | +GoodputSampling (std::string fileName, ApplicationContainer n3App, Ptr<OutputStreamWrapper> goodputStream, float samplingPeriod) |
| 83 | +{ |
| 84 | + Simulator::Schedule (Seconds (samplingPeriod), &GoodputSampling, fileName, n3App, goodputStream, samplingPeriod); |
| 85 | + double goodput[4]; |
| 86 | + for (int i = 0; i < 4; i++) |
| 87 | + { |
| 88 | + uint32_t totalPackets = DynamicCast<PacketSink> (n3App.Get (i))->GetTotalRx (); |
| 89 | + goodput[i] = totalPackets * 8 / (Simulator::Now ().GetSeconds () * 1024); // Kbit/s |
| 90 | + } |
| 91 | + *goodputStream->GetStream () << Simulator::Now ().GetSeconds () << " " << goodput[0] << " " << goodput[1] << " " |
| 92 | + << goodput[2] << " " << goodput[3] << std::endl; |
| 93 | +} |
| 94 | + |
| 95 | +static void PingRtt (std::string context, Time rtt) |
| 96 | +{ |
| 97 | + std::cout << context << "=" << rtt.GetMilliSeconds () << " ms" << std::endl; |
| 98 | +} |
| 99 | + |
| 100 | +int main (int argc, char *argv[]) |
| 101 | +{ |
| 102 | + std::string bottleneckBandwidth = "10Mbps"; |
| 103 | + std::string bottleneckDelay = "5ms"; |
| 104 | + std::string bottleneckQueueDiscType = "PfifoFast"; |
| 105 | + uint32_t bottleneckQueueDiscSize = 1000; |
| 106 | + uint32_t bottleneckNetdevicesQueueSize = 100; |
| 107 | + bool bottleneckBql = false; |
| 108 | + float startTime = 0.1; // in s |
| 109 | + float simDuration = 60; |
| 110 | + float samplingPeriod = 1; |
| 111 | + |
| 112 | + // RRUL-like flows configuration with 4 upload + 4 download flows |
| 113 | + std::string rates[4]; |
| 114 | + rates[0] = "4Mbps"; |
| 115 | + rates[1] = "2Mbps"; |
| 116 | + rates[2] = "4Mbps"; |
| 117 | + rates[3] = "2Mbps"; |
| 118 | + uint32_t sizes[4]; |
| 119 | + sizes[0] = 1460; |
| 120 | + sizes[1] = 1460; |
| 121 | + sizes[2] = 1460; |
| 122 | + sizes[3] = 1460; |
| 123 | + uint8_t priorities[4]; |
| 124 | + priorities[0] = 0x00; // Best effort |
| 125 | + priorities[1] = 0x28; // CS5 |
| 126 | + priorities[2] = 0x2E; // EF |
| 127 | + priorities[3] = 0x0A; // Bulk |
| 128 | + |
| 129 | + CommandLine cmd; |
| 130 | + cmd.AddValue ("bottleneckBandwidth", "Bottleneck bandwidth", bottleneckBandwidth); |
| 131 | + cmd.AddValue ("bottleneckDelay", "Bottleneck delay", bottleneckDelay); |
| 132 | + cmd.AddValue ("bottleneckQueueDiscType", "Queue disc type: PfifoFast, ARED, CoDel", bottleneckQueueDiscType); |
| 133 | + cmd.AddValue ("bottleneckQueueDiscSize", "Queue disc size in packets", bottleneckQueueDiscSize); |
| 134 | + cmd.AddValue ("bottleneckNetdevicesQueueSize", "Queue size in packets", bottleneckNetdevicesQueueSize); |
| 135 | + cmd.AddValue ("bottleneckBql", "Enable byte queue limits on bottleneck netdevices", bottleneckBql); |
| 136 | + cmd.AddValue ("startTime", "Simulation start time", startTime); |
| 137 | + cmd.AddValue ("simDuration", "Simulation duration in seconds", simDuration); |
| 138 | + cmd.Parse (argc, argv); |
| 139 | + |
| 140 | + float stopTime = startTime + simDuration; |
| 141 | + |
| 142 | + // Create nodes |
| 143 | + NodeContainer n1, n2, n3; |
| 144 | + n1.Create (1); |
| 145 | + n2.Create (1); |
| 146 | + n3.Create (1); |
| 147 | + |
| 148 | + // Create and configure access link and bottleneck link |
| 149 | + PointToPointHelper accessLink; |
| 150 | + accessLink.SetDeviceAttribute ("DataRate", StringValue ("100Mbps")); |
| 151 | + accessLink.SetChannelAttribute ("Delay", StringValue ("0.1ms")); |
| 152 | + |
| 153 | + PointToPointHelper bottleneckLink; |
| 154 | + bottleneckLink.SetDeviceAttribute ("DataRate", StringValue (bottleneckBandwidth)); |
| 155 | + bottleneckLink.SetChannelAttribute ("Delay", StringValue (bottleneckDelay)); |
| 156 | + |
| 157 | + InternetStackHelper stack; |
| 158 | + stack.InstallAll (); |
| 159 | + |
| 160 | + // Access link traffic control configuration |
| 161 | + TrafficControlHelper tchPfifoFastAccess; |
| 162 | + uint32_t handle = tchPfifoFastAccess.SetRootQueueDisc ("ns3::PfifoFastQueueDisc", "Limit", UintegerValue (1000)); |
| 163 | + |
| 164 | + // Bottleneck link traffic control configuration |
| 165 | + TrafficControlHelper tchPfifoFastBottleneck; |
| 166 | + handle = tchPfifoFastBottleneck.SetRootQueueDisc ("ns3::PfifoFastQueueDisc", "Limit", UintegerValue (bottleneckQueueDiscSize)); |
| 167 | + |
| 168 | + TrafficControlHelper tchRed; |
| 169 | + handle = tchRed.SetRootQueueDisc ("ns3::RedQueueDisc"); |
| 170 | + Config::SetDefault ("ns3::RedQueueDisc::ARED", BooleanValue (true)); |
| 171 | + tchRed.AddInternalQueues (handle, 1, "ns3::DropTailQueue", "MaxPackets", UintegerValue (bottleneckQueueDiscSize)); |
| 172 | + |
| 173 | + TrafficControlHelper tchCoDel; |
| 174 | + handle = tchCoDel.SetRootQueueDisc ("ns3::CoDelQueueDisc"); |
| 175 | + Config::SetDefault ("ns3::CoDelQueueDisc::Mode", EnumValue (Queue::QUEUE_MODE_PACKETS)); |
| 176 | + tchCoDel.AddInternalQueues (handle, 1, "ns3::DropTailQueue", "MaxPackets", UintegerValue (bottleneckQueueDiscSize)); |
| 177 | + |
| 178 | + if (bottleneckBql) |
| 179 | + { |
| 180 | + tchPfifoFastBottleneck.SetQueueLimits ("ns3::DynamicQueueLimits"); |
| 181 | + tchRed.SetQueueLimits ("ns3::DynamicQueueLimits"); |
| 182 | + tchCoDel.SetQueueLimits ("ns3::DynamicQueueLimits"); |
| 183 | + } |
| 184 | + |
| 185 | + Config::SetDefault ("ns3::Queue::Mode", StringValue ("QUEUE_MODE_PACKETS")); |
| 186 | + Config::SetDefault ("ns3::Queue::MaxPackets", UintegerValue (100)); |
| 187 | + |
| 188 | + NetDeviceContainer devicesAccessLink = accessLink.Install (n1.Get (0), n2.Get (0)); |
| 189 | + tchPfifoFastAccess.Install (devicesAccessLink); |
| 190 | + Ipv4AddressHelper address; |
| 191 | + address.SetBase ("192.168.0.0", "255.255.255.0"); |
| 192 | + address.NewNetwork (); |
| 193 | + Ipv4InterfaceContainer interfacesAccess = address.Assign (devicesAccessLink); |
| 194 | + |
| 195 | + Config::SetDefault ("ns3::Queue::MaxPackets", UintegerValue (bottleneckNetdevicesQueueSize)); |
| 196 | + |
| 197 | + NetDeviceContainer devicesBottleneckLink = bottleneckLink.Install (n2.Get (0), n3.Get (0)); |
| 198 | + QueueDiscContainer qdiscs; |
| 199 | + if (bottleneckQueueDiscType.compare ("PfifoFast") == 0) |
| 200 | + { |
| 201 | + qdiscs = tchPfifoFastBottleneck.Install (devicesBottleneckLink); |
| 202 | + } |
| 203 | + else if (bottleneckQueueDiscType.compare ("ARED") == 0) |
| 204 | + { |
| 205 | + qdiscs = tchRed.Install (devicesBottleneckLink); |
| 206 | + } |
| 207 | + else if (bottleneckQueueDiscType.compare ("CoDel") == 0) |
| 208 | + { |
| 209 | + qdiscs = tchCoDel.Install (devicesBottleneckLink); |
| 210 | + } |
| 211 | + else |
| 212 | + { |
| 213 | + NS_ABORT_MSG ("--bottleneckQueueDiscType not valid"); |
| 214 | + } |
| 215 | + address.NewNetwork (); |
| 216 | + Ipv4InterfaceContainer interfacesBottleneck = address.Assign (devicesBottleneckLink); |
| 217 | + |
| 218 | + Ptr<NetDeviceQueueInterface> interface = devicesBottleneckLink.Get (0)->GetObject<NetDeviceQueueInterface> (); |
| 219 | + Ptr<NetDeviceQueue> queueInterface = interface->GetTxQueue (0); |
| 220 | + Ptr<DynamicQueueLimits> queueLimits = StaticCast<DynamicQueueLimits> (queueInterface->GetQueueLimits ()); |
| 221 | + |
| 222 | + AsciiTraceHelper ascii; |
| 223 | + if (bottleneckBql) |
| 224 | + { |
| 225 | + bottleneckQueueDiscType = bottleneckQueueDiscType + "-bql"; |
| 226 | + Ptr<OutputStreamWrapper> streamLimits = ascii.CreateFileStream (bottleneckQueueDiscType + "-limits.txt"); |
| 227 | + queueLimits->TraceConnectWithoutContext ("Limit",MakeBoundCallback (&LimitsTrace, streamLimits)); |
| 228 | + } |
| 229 | + Ptr<Queue> queue = StaticCast<PointToPointNetDevice> (devicesBottleneckLink.Get (0))->GetQueue (); |
| 230 | + Ptr<OutputStreamWrapper> streamBytesInQueue = ascii.CreateFileStream (bottleneckQueueDiscType + "-bytesInQueue.txt"); |
| 231 | + queue->TraceConnectWithoutContext ("BytesInQueue",MakeBoundCallback (&BytesInQueueTrace, streamBytesInQueue)); |
| 232 | + |
| 233 | + Ipv4InterfaceContainer n1Interface; |
| 234 | + n1Interface.Add (interfacesAccess.Get (0)); |
| 235 | + |
| 236 | + Ipv4InterfaceContainer n3Interface; |
| 237 | + n3Interface.Add (interfacesBottleneck.Get (1)); |
| 238 | + |
| 239 | + Ipv4GlobalRoutingHelper::PopulateRoutingTables (); |
| 240 | + |
| 241 | + uint32_t segmentSize = std::max (std::max (std::max (sizes[0], sizes[1]), sizes[2]), sizes[3]); |
| 242 | + Config::SetDefault ("ns3::TcpSocket::SegmentSize", UintegerValue (segmentSize)); |
| 243 | + |
| 244 | + uint16_t port = 7; |
| 245 | + ApplicationContainer uploadApps, downloadApps, sourceApps; |
| 246 | + // Configure and install upload flows |
| 247 | + for (int i = 0; i < 4; i++) |
| 248 | + { |
| 249 | + Address add (InetSocketAddress (Ipv4Address::GetAny (), port + i)); |
| 250 | + PacketSinkHelper sinkHelper ("ns3::TcpSocketFactory", add); |
| 251 | + sinkHelper.SetAttribute ("Protocol", TypeIdValue (TcpSocketFactory::GetTypeId ())); |
| 252 | + uploadApps.Add (sinkHelper.Install (n3)); |
| 253 | + |
| 254 | + InetSocketAddress socketAddress = InetSocketAddress (n3Interface.GetAddress (0), port + i); |
| 255 | + socketAddress.SetTos (priorities [i]); |
| 256 | + OnOffHelper onOffHelper ("ns3::TcpSocketFactory", Address ()); |
| 257 | + onOffHelper.SetAttribute ("Remote", AddressValue (socketAddress)); |
| 258 | + onOffHelper.SetAttribute ("OnTime", StringValue ("ns3::ConstantRandomVariable[Constant=1]")); |
| 259 | + onOffHelper.SetAttribute ("OffTime", StringValue ("ns3::ConstantRandomVariable[Constant=0]")); |
| 260 | + onOffHelper.SetAttribute ("PacketSize", UintegerValue (sizes [i])); |
| 261 | + onOffHelper.SetAttribute ("DataRate", StringValue (rates [i])); |
| 262 | + sourceApps.Add (onOffHelper.Install (n1)); |
| 263 | + } |
| 264 | + |
| 265 | + port = 11; |
| 266 | + // Configure and install download flows |
| 267 | + for (int i = 0; i < 4; i++) |
| 268 | + { |
| 269 | + Address add (InetSocketAddress (Ipv4Address::GetAny (), port + i)); |
| 270 | + PacketSinkHelper sinkHelper ("ns3::TcpSocketFactory", add); |
| 271 | + sinkHelper.SetAttribute ("Protocol", TypeIdValue (TcpSocketFactory::GetTypeId ())); |
| 272 | + downloadApps.Add (sinkHelper.Install (n1)); |
| 273 | + |
| 274 | + InetSocketAddress socketAddress = InetSocketAddress (n1Interface.GetAddress (0), port + i); |
| 275 | + socketAddress.SetTos (priorities [i]); |
| 276 | + OnOffHelper onOffHelper ("ns3::TcpSocketFactory", Address ()); |
| 277 | + onOffHelper.SetAttribute ("Remote", AddressValue (socketAddress)); |
| 278 | + onOffHelper.SetAttribute ("OnTime", StringValue ("ns3::ConstantRandomVariable[Constant=1]")); |
| 279 | + onOffHelper.SetAttribute ("OffTime", StringValue ("ns3::ConstantRandomVariable[Constant=0]")); |
| 280 | + onOffHelper.SetAttribute ("PacketSize", UintegerValue (sizes [i])); |
| 281 | + onOffHelper.SetAttribute ("DataRate", StringValue (rates [i])); |
| 282 | + sourceApps.Add (onOffHelper.Install (n3)); |
| 283 | + } |
| 284 | + |
| 285 | + // Configure and install ping |
| 286 | + V4PingHelper ping = V4PingHelper (n3Interface.GetAddress (0)); |
| 287 | + ping.Install (n1); |
| 288 | + |
| 289 | + Config::Connect ("/NodeList/*/ApplicationList/*/$ns3::V4Ping/Rtt", MakeCallback (&PingRtt)); |
| 290 | + |
| 291 | + uploadApps.Start (Seconds (0)); |
| 292 | + uploadApps.Stop (Seconds (stopTime)); |
| 293 | + downloadApps.Start (Seconds (0)); |
| 294 | + downloadApps.Stop (Seconds (stopTime)); |
| 295 | + |
| 296 | + sourceApps.Start (Seconds (0 + 0.1)); |
| 297 | + sourceApps.Stop (Seconds (stopTime - 0.1)); |
| 298 | + |
| 299 | + Ptr<OutputStreamWrapper> uploadGoodputStream = ascii.CreateFileStream (bottleneckQueueDiscType + "-upload-goodput.txt"); |
| 300 | + Simulator::Schedule (Seconds (samplingPeriod), &GoodputSampling, bottleneckQueueDiscType + "-upload-goodput.txt", uploadApps, |
| 301 | + uploadGoodputStream, samplingPeriod); |
| 302 | + Ptr<OutputStreamWrapper> downloadGoodputStream = ascii.CreateFileStream (bottleneckQueueDiscType + "-download-goodput.txt"); |
| 303 | + Simulator::Schedule (Seconds (samplingPeriod), &GoodputSampling, bottleneckQueueDiscType + "-download-goodput.txt", downloadApps, |
| 304 | + downloadGoodputStream, samplingPeriod); |
| 305 | + |
| 306 | + // Flow monitor |
| 307 | + Ptr<FlowMonitor> flowMonitor; |
| 308 | + FlowMonitorHelper flowHelper; |
| 309 | + flowMonitor = flowHelper.InstallAll(); |
| 310 | + |
| 311 | + Simulator::Stop (Seconds (stopTime)); |
| 312 | + Simulator::Run (); |
| 313 | + |
| 314 | + flowMonitor->SerializeToXmlFile(bottleneckQueueDiscType + "-flowMonitor.xml", true, true); |
| 315 | + |
| 316 | + Simulator::Destroy (); |
| 317 | + return 0; |
| 318 | +} |
0 commit comments