From b0b03f081cadeeca4e965a5e697e5f1b30316729 Mon Sep 17 00:00:00 2001 From: M P Tahiliani Date: Tue, 8 Mar 2016 10:48:41 -0800 Subject: [PATCH] traffic-control: Add ARED test and examples --- .../examples/adaptive-red-tests.cc | 703 ++++++++++++++++++ src/traffic-control/examples/red-vs-ared.cc | 244 ++++++ src/traffic-control/examples/wscript | 6 + .../adaptive-red-queue-disc-test-suite.cc | 492 ++++++++++++ src/traffic-control/wscript | 1 + 5 files changed, 1446 insertions(+) create mode 100644 src/traffic-control/examples/adaptive-red-tests.cc create mode 100644 src/traffic-control/examples/red-vs-ared.cc create mode 100644 src/traffic-control/test/adaptive-red-queue-disc-test-suite.cc diff --git a/src/traffic-control/examples/adaptive-red-tests.cc b/src/traffic-control/examples/adaptive-red-tests.cc new file mode 100644 index 000000000..218c26392 --- /dev/null +++ b/src/traffic-control/examples/adaptive-red-tests.cc @@ -0,0 +1,703 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2015 NITK Surathkal + * + * 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: Mohit P. Tahiliani + * + */ + +/** + * NOTE: These validation tests are same as provided in ns-2 + * (ns/tcl/test/test-suite-adaptive-red.tcl) + * + * In this code, tests 1, 2, 6, 7, 8, 9, 10, 12, 13, 14 and 15 refer to tests + * named red1, red1Adapt, fastlink, fastlinkAutowq, fastlinkAutothresh, + * fastlinkAdaptive, fastlinkAllAdapt, fastlinkAllAdapt1, longlink, + * longlinkAdapt and longlinkAdapt1, respectively in the ns-2 file + * mentioned above. + */ + +/** Network topology for tests: 1 and 2 + * + * 10Mb/s, 2ms 10Mb/s, 4ms + * n0--------------| |---------------n4 + * | 1.5Mbps, 20ms | + * n2------------------n3 + * 10Mb/s, 3ms | QueueLimit = 25 | 10Mb/s, 5ms + * n1--------------| |---------------n5 + * + */ + +/** Network topology for tests: 6, 7, 8, 9, 10 and 12 + * + * 100Mb/s, 2ms 100Mb/s, 4ms + * n0--------------| |---------------n4 + * | 15Mbps, 20ms | + * n2------------------n3 + * 100Mb/s, 3ms | QueueLimit = 1000 | 100Mb/s, 5ms + * n1--------------| |---------------n5 + * + */ + +/** Network topology for tests: 13, 14 and 15 +* +* 10Mb/s, 0ms 10Mb/s, 2ms +* n0--------------| |---------------n4 +* | 1.5Mbps, 100ms | +* n2------------------n3 +* 10Mb/s, 1ms | QueueLimit = 100 | 10Mb/s, 3ms +* n1--------------| |---------------n5 +* +*/ + +#include "ns3/core-module.h" +#include "ns3/network-module.h" +#include "ns3/internet-module.h" +#include "ns3/flow-monitor-helper.h" +#include "ns3/point-to-point-module.h" +#include "ns3/applications-module.h" +#include "ns3/traffic-control-module.h" + +using namespace ns3; + +NS_LOG_COMPONENT_DEFINE ("AdaptiveRedTests"); + +uint32_t checkTimes; +double avgQueueDiscSize; + +// The times +double global_start_time; +double global_stop_time; +double sink_start_time; +double sink_stop_time; +double client_start_time; +double client_stop_time; + +NodeContainer n0n2; +NodeContainer n1n2; +NodeContainer n2n3; +NodeContainer n3n4; +NodeContainer n3n5; + +Ipv4InterfaceContainer i0i2; +Ipv4InterfaceContainer i1i2; +Ipv4InterfaceContainer i2i3; +Ipv4InterfaceContainer i3i4; +Ipv4InterfaceContainer i3i5; + +std::stringstream filePlotQueueDisc; +std::stringstream filePlotQueueDiscAvg; + +void +CheckQueueDiscSize (Ptr queue) +{ + uint32_t qSize = StaticCast (queue)->GetQueueSize (); + + avgQueueDiscSize += qSize; + checkTimes++; + + // check queue disc size every 1/100 of a second + Simulator::Schedule (Seconds (0.01), &CheckQueueDiscSize, queue); + + std::ofstream fPlotQueueDisc (filePlotQueueDisc.str ().c_str (), std::ios::out | std::ios::app); + fPlotQueueDisc << Simulator::Now ().GetSeconds () << " " << qSize << std::endl; + fPlotQueueDisc.close (); + + std::ofstream fPlotQueueDiscAvg (filePlotQueueDiscAvg.str ().c_str (), std::ios::out | std::ios::app); + fPlotQueueDiscAvg << Simulator::Now ().GetSeconds () << " " << avgQueueDiscSize / checkTimes << std::endl; + fPlotQueueDiscAvg.close (); +} + +void +BuildAppsTest (uint32_t test) +{ + // SINK is in the right side + uint16_t port = 50000; + Address sinkLocalAddress (InetSocketAddress (Ipv4Address::GetAny (), port)); + PacketSinkHelper sinkHelper ("ns3::TcpSocketFactory", sinkLocalAddress); + ApplicationContainer sinkApp = sinkHelper.Install (n3n4.Get (1)); + sinkApp.Start (Seconds (sink_start_time)); + sinkApp.Stop (Seconds (sink_stop_time)); + + // Connection one + // Clients are in left side + /* + * Create the OnOff applications to send TCP to the server + * onoffhelper is a client that send data to TCP destination + */ + OnOffHelper clientHelper1 ("ns3::TcpSocketFactory", Address ()); + clientHelper1.SetAttribute ("OnTime", StringValue ("ns3::ConstantRandomVariable[Constant=1]")); + clientHelper1.SetAttribute ("OffTime", StringValue ("ns3::ConstantRandomVariable[Constant=0]")); + clientHelper1.SetAttribute ("PacketSize", UintegerValue (1000)); + + // Connection two + OnOffHelper clientHelper2 ("ns3::TcpSocketFactory", Address ()); + clientHelper2.SetAttribute ("OnTime", StringValue ("ns3::ConstantRandomVariable[Constant=1]")); + clientHelper2.SetAttribute ("OffTime", StringValue ("ns3::ConstantRandomVariable[Constant=0]")); + clientHelper2.SetAttribute ("PacketSize", UintegerValue (1000)); + + if (test == 6 || test == 7 || test == 8 || test == 9 || test == 10 || test == 12) + { + clientHelper1.SetAttribute ("DataRate", DataRateValue (DataRate ("100Mb/s"))); + clientHelper2.SetAttribute ("DataRate", DataRateValue (DataRate ("100Mb/s"))); + } + else + { + clientHelper1.SetAttribute ("DataRate", DataRateValue (DataRate ("10Mb/s"))); + clientHelper2.SetAttribute ("DataRate", DataRateValue (DataRate ("10Mb/s"))); + } + + ApplicationContainer clientApps1; + AddressValue remoteAddress (InetSocketAddress (i3i4.GetAddress (1), port)); + clientHelper1.SetAttribute ("Remote", remoteAddress); + clientApps1.Add (clientHelper1.Install (n0n2.Get (0))); + clientApps1.Start (Seconds (client_start_time)); + clientApps1.Stop (Seconds (client_stop_time)); + + ApplicationContainer clientApps2; + clientHelper2.SetAttribute ("Remote", remoteAddress); + clientApps2.Add (clientHelper2.Install (n1n2.Get (0))); + clientApps2.Start (Seconds (client_start_time)); + clientApps2.Stop (Seconds (client_stop_time)); +} + +int +main (int argc, char *argv[]) +{ + LogComponentEnable ("RedQueueDisc", LOG_LEVEL_INFO); + + uint32_t aredTest; + std::string aredLinkDataRate = "1.5Mbps"; + std::string aredLinkDelay = "20ms"; + + std::string pathOut; + bool writeForPlot = false; + bool writePcap = false; + bool flowMonitor = false; + + bool printAredStats = true; + + global_start_time = 0.0; + sink_start_time = global_start_time; + client_start_time = global_start_time + 1.5; + global_stop_time = 7.0; + sink_stop_time = global_stop_time + 3.0; + client_stop_time = global_stop_time - 2.0; + + // Configuration and command line parameter parsing + aredTest = 1; + // Will only save in the directory if enable opts below + pathOut = "."; // Current directory + CommandLine cmd; + cmd.AddValue ("testNumber", "Run test 1, 2, 6, 7, 8, 9, 10, 12, 13, 14 or 15", aredTest); + cmd.AddValue ("pathOut", "Path to save results from --writeForPlot/--writePcap/--writeFlowMonitor", pathOut); + cmd.AddValue ("writeForPlot", "<0/1> to write results for plot (gnuplot)", writeForPlot); + cmd.AddValue ("writePcap", "<0/1> to write results in pcapfile", writePcap); + cmd.AddValue ("writeFlowMonitor", "<0/1> to enable Flow Monitor and write their results", flowMonitor); + + cmd.Parse (argc, argv); + if ( (aredTest != 1) && (aredTest != 2) && (aredTest != 6) && (aredTest != 7) && (aredTest != 8) && (aredTest != 9) && (aredTest != 10) && (aredTest != 12) && (aredTest != 13) && (aredTest != 14) && (aredTest != 15) ) + { + std::cout << "Invalid test number. Supported tests are 1, 2, 6, 7, 8, 9, 10, 12, 13, 14 or 15" << std::endl; + exit (1); + } + + NS_LOG_INFO ("Create nodes"); + NodeContainer c; + c.Create (6); + Names::Add ( "N0", c.Get (0)); + Names::Add ( "N1", c.Get (1)); + Names::Add ( "N2", c.Get (2)); + Names::Add ( "N3", c.Get (3)); + Names::Add ( "N4", c.Get (4)); + Names::Add ( "N5", c.Get (5)); + n0n2 = NodeContainer (c.Get (0), c.Get (2)); + n1n2 = NodeContainer (c.Get (1), c.Get (2)); + n2n3 = NodeContainer (c.Get (2), c.Get (3)); + n3n4 = NodeContainer (c.Get (3), c.Get (4)); + n3n5 = NodeContainer (c.Get (3), c.Get (5)); + + Config::SetDefault ("ns3::TcpL4Protocol::SocketType", StringValue ("ns3::TcpNewReno")); + // 42 = headers size + Config::SetDefault ("ns3::TcpSocket::SegmentSize", UintegerValue (1000 - 42)); + Config::SetDefault ("ns3::TcpSocket::DelAckCount", UintegerValue (1)); + GlobalValue::Bind ("ChecksumEnabled", BooleanValue (false)); + + uint32_t meanPktSize = 1000; + + // RED params + NS_LOG_INFO ("Set RED params"); + Config::SetDefault ("ns3::RedQueueDisc::Mode", StringValue ("QUEUE_MODE_PACKETS")); + Config::SetDefault ("ns3::RedQueueDisc::MeanPktSize", UintegerValue (meanPktSize)); + Config::SetDefault ("ns3::RedQueueDisc::Wait", BooleanValue (true)); + Config::SetDefault ("ns3::RedQueueDisc::Gentle", BooleanValue (true)); + Config::SetDefault ("ns3::RedQueueDisc::QW", DoubleValue (0.002)); + Config::SetDefault ("ns3::RedQueueDisc::MinTh", DoubleValue (5)); + Config::SetDefault ("ns3::RedQueueDisc::MaxTh", DoubleValue (15)); + Config::SetDefault ("ns3::RedQueueDisc::QueueLimit", UintegerValue (1000)); + + if (aredTest == 1) // test 1: red1 + { + Config::SetDefault ("ns3::RedQueueDisc::QueueLimit", UintegerValue (25)); + } + else if (aredTest == 2) // test 2: red1Adapt + { + Config::SetDefault ("ns3::RedQueueDisc::ARED", BooleanValue (true)); + Config::SetDefault ("ns3::RedQueueDisc::LInterm", DoubleValue (10)); + Config::SetDefault ("ns3::RedQueueDisc::QueueLimit", UintegerValue (25)); + } + else if (aredTest == 7) // test 7: fastlinkAutowq + { + Config::SetDefault ("ns3::RedQueueDisc::QW", DoubleValue (0.0)); + } + else if (aredTest == 8) // test 8: fastlinkAutothresh + { + Config::SetDefault ("ns3::RedQueueDisc::MinTh", DoubleValue (0)); + Config::SetDefault ("ns3::RedQueueDisc::MaxTh", DoubleValue (0)); + } + else if (aredTest == 9) // test 9: fastlinkAdaptive + { + Config::SetDefault ("ns3::RedQueueDisc::AdaptMaxP", BooleanValue (true)); + Config::SetDefault ("ns3::RedQueueDisc::LInterm", DoubleValue (10)); + } + else if (aredTest == 10) // test 10: fastlinkAllAdapt + { + Config::SetDefault ("ns3::RedQueueDisc::ARED", BooleanValue (true)); + Config::SetDefault ("ns3::RedQueueDisc::LInterm", DoubleValue (10)); + } + else if (aredTest == 12) // test 12: fastlinkAllAdapt1 + { + Config::SetDefault ("ns3::RedQueueDisc::ARED", BooleanValue (true)); + Config::SetDefault ("ns3::RedQueueDisc::LInterm", DoubleValue (10)); + Config::SetDefault ("ns3::RedQueueDisc::TargetDelay", TimeValue (Seconds (0.2))); + } + else if (aredTest == 13) // test 13: longlink + { + Config::SetDefault ("ns3::RedQueueDisc::QueueLimit", UintegerValue (100)); + } + else if (aredTest == 14) // test 14: longlinkAdapt + { + Config::SetDefault ("ns3::RedQueueDisc::ARED", BooleanValue (true)); + Config::SetDefault ("ns3::RedQueueDisc::LInterm", DoubleValue (10)); + Config::SetDefault ("ns3::RedQueueDisc::QueueLimit", UintegerValue (100)); + } + else if (aredTest == 15) // test 15: longlinkAdapt1 + { + Config::SetDefault ("ns3::RedQueueDisc::QW", DoubleValue (-1.0)); + Config::SetDefault ("ns3::RedQueueDisc::MinTh", DoubleValue (0)); + Config::SetDefault ("ns3::RedQueueDisc::MaxTh", DoubleValue (0)); + Config::SetDefault ("ns3::RedQueueDisc::AdaptMaxP", BooleanValue (true)); + Config::SetDefault ("ns3::RedQueueDisc::LInterm", DoubleValue (10)); + Config::SetDefault ("ns3::RedQueueDisc::QueueLimit", UintegerValue (100)); + } + + NS_LOG_INFO ("Install internet stack on all nodes."); + InternetStackHelper internet; + internet.Install (c); + + TrafficControlHelper tchPfifo; + uint16_t handle = tchPfifo.SetRootQueueDisc ("ns3::PfifoFastQueueDisc"); + tchPfifo.AddInternalQueues (handle, 3, "ns3::DropTailQueue", "MaxPackets", UintegerValue (1000)); + tchPfifo.AddPacketFilter (handle, "ns3::PfifoFastIpv4PacketFilter"); + + TrafficControlHelper tchRed; + tchRed.SetRootQueueDisc ("ns3::RedQueueDisc", "LinkBandwidth", StringValue (aredLinkDataRate), + "LinkDelay", StringValue (aredLinkDelay)); + + NS_LOG_INFO ("Create channels"); + PointToPointHelper p2p; + + NetDeviceContainer devn0n2; + NetDeviceContainer devn1n2; + NetDeviceContainer devn2n3; + NetDeviceContainer devn3n4; + NetDeviceContainer devn3n5; + + QueueDiscContainer queueDiscs; + + if (aredTest == 1 || aredTest == 2) + { + p2p.SetQueue ("ns3::DropTailQueue"); + p2p.SetDeviceAttribute ("DataRate", StringValue ("10Mbps")); + p2p.SetChannelAttribute ("Delay", StringValue ("2ms")); + devn0n2 = p2p.Install (n0n2); + tchPfifo.Install (devn0n2); + + p2p.SetQueue ("ns3::DropTailQueue"); + p2p.SetDeviceAttribute ("DataRate", StringValue ("10Mbps")); + p2p.SetChannelAttribute ("Delay", StringValue ("3ms")); + devn1n2 = p2p.Install (n1n2); + tchPfifo.Install (devn1n2); + + p2p.SetQueue ("ns3::DropTailQueue"); + p2p.SetDeviceAttribute ("DataRate", StringValue (aredLinkDataRate)); + p2p.SetChannelAttribute ("Delay", StringValue (aredLinkDelay)); + devn2n3 = p2p.Install (n2n3); + // only backbone link has ARED queue disc + queueDiscs = tchRed.Install (devn2n3); + + p2p.SetQueue ("ns3::DropTailQueue"); + p2p.SetDeviceAttribute ("DataRate", StringValue ("10Mbps")); + p2p.SetChannelAttribute ("Delay", StringValue ("4ms")); + devn3n4 = p2p.Install (n3n4); + tchPfifo.Install (devn3n4); + + p2p.SetQueue ("ns3::DropTailQueue"); + p2p.SetDeviceAttribute ("DataRate", StringValue ("10Mbps")); + p2p.SetChannelAttribute ("Delay", StringValue ("5ms")); + devn3n5 = p2p.Install (n3n5); + tchPfifo.Install (devn3n5); + } + else if (aredTest == 13 || aredTest == 14 || aredTest == 15) + { + p2p.SetQueue ("ns3::DropTailQueue"); + p2p.SetDeviceAttribute ("DataRate", StringValue ("10Mbps")); + p2p.SetChannelAttribute ("Delay", StringValue ("0ms")); + devn0n2 = p2p.Install (n0n2); + tchPfifo.Install (devn0n2); + + p2p.SetQueue ("ns3::DropTailQueue"); + p2p.SetDeviceAttribute ("DataRate", StringValue ("10Mbps")); + p2p.SetChannelAttribute ("Delay", StringValue ("1ms")); + devn1n2 = p2p.Install (n1n2); + tchPfifo.Install (devn1n2); + + p2p.SetQueue ("ns3::DropTailQueue"); + p2p.SetDeviceAttribute ("DataRate", StringValue (aredLinkDataRate)); + p2p.SetChannelAttribute ("Delay", StringValue ("100ms")); + devn2n3 = p2p.Install (n2n3); + // only backbone link has ARED queue disc + queueDiscs = tchRed.Install (devn2n3); + + p2p.SetQueue ("ns3::DropTailQueue"); + p2p.SetDeviceAttribute ("DataRate", StringValue ("10Mbps")); + p2p.SetChannelAttribute ("Delay", StringValue ("2ms")); + devn3n4 = p2p.Install (n3n4); + tchPfifo.Install (devn3n4); + + p2p.SetQueue ("ns3::DropTailQueue"); + p2p.SetDeviceAttribute ("DataRate", StringValue ("10Mbps")); + p2p.SetChannelAttribute ("Delay", StringValue ("3ms")); + devn3n5 = p2p.Install (n3n5); + tchPfifo.Install (devn3n5); + } + else if (aredTest == 6 || aredTest == 7 || aredTest == 8 || aredTest == 9 || aredTest == 10 || aredTest == 12) + { + p2p.SetQueue ("ns3::DropTailQueue"); + p2p.SetDeviceAttribute ("DataRate", StringValue ("100Mbps")); + p2p.SetChannelAttribute ("Delay", StringValue ("2ms")); + devn0n2 = p2p.Install (n0n2); + tchPfifo.Install (devn0n2); + + p2p.SetQueue ("ns3::DropTailQueue"); + p2p.SetDeviceAttribute ("DataRate", StringValue ("100Mbps")); + p2p.SetChannelAttribute ("Delay", StringValue ("3ms")); + devn1n2 = p2p.Install (n1n2); + tchPfifo.Install (devn1n2); + + p2p.SetQueue ("ns3::DropTailQueue"); + p2p.SetDeviceAttribute ("DataRate", StringValue ("15Mbps")); + p2p.SetChannelAttribute ("Delay", StringValue (aredLinkDelay)); + devn2n3 = p2p.Install (n2n3); + // only backbone link has ARED queue disc + queueDiscs = tchRed.Install (devn2n3); + + p2p.SetQueue ("ns3::DropTailQueue"); + p2p.SetDeviceAttribute ("DataRate", StringValue ("100Mbps")); + p2p.SetChannelAttribute ("Delay", StringValue ("4ms")); + devn3n4 = p2p.Install (n3n4); + tchPfifo.Install (devn3n4); + + p2p.SetQueue ("ns3::DropTailQueue"); + p2p.SetDeviceAttribute ("DataRate", StringValue ("100Mbps")); + p2p.SetChannelAttribute ("Delay", StringValue ("5ms")); + devn3n5 = p2p.Install (n3n5); + tchPfifo.Install (devn3n5); + } + + NS_LOG_INFO ("Assign IP Addresses"); + Ipv4AddressHelper ipv4; + + ipv4.SetBase ("10.1.1.0", "255.255.255.0"); + i0i2 = ipv4.Assign (devn0n2); + + ipv4.SetBase ("10.1.2.0", "255.255.255.0"); + i1i2 = ipv4.Assign (devn1n2); + + ipv4.SetBase ("10.1.3.0", "255.255.255.0"); + i2i3 = ipv4.Assign (devn2n3); + + ipv4.SetBase ("10.1.4.0", "255.255.255.0"); + i3i4 = ipv4.Assign (devn3n4); + + ipv4.SetBase ("10.1.5.0", "255.255.255.0"); + i3i5 = ipv4.Assign (devn3n5); + + // Set up the routing + Ipv4GlobalRoutingHelper::PopulateRoutingTables (); + + BuildAppsTest (aredTest); + + if (writePcap) + { + PointToPointHelper ptp; + std::stringstream stmp; + stmp << pathOut << "/ared"; + ptp.EnablePcapAll (stmp.str ().c_str ()); + } + + Ptr flowmon; + if (flowMonitor) + { + FlowMonitorHelper flowmonHelper; + flowmon = flowmonHelper.InstallAll (); + } + + if (writeForPlot) + { + filePlotQueueDisc << pathOut << "/" << "ared-queue-disc.plotme"; + filePlotQueueDiscAvg << pathOut << "/" << "ared-queue-disc_avg.plotme"; + + remove (filePlotQueueDisc.str ().c_str ()); + remove (filePlotQueueDiscAvg.str ().c_str ()); + Ptr queue = queueDiscs.Get (0); + Simulator::ScheduleNow (&CheckQueueDiscSize, queue); + } + + Simulator::Stop (Seconds (sink_stop_time)); + Simulator::Run (); + + RedQueueDisc::Stats st = StaticCast (queueDiscs.Get (0))->GetStats (); + + if (aredTest == 1) + { + if (st.unforcedDrop > 2) + { + std::cout << "Drops due to prob mark should be around 1" << std::endl; + exit (-1); + } + else if (st.forcedDrop < 137 || st.forcedDrop > 139) + { + std::cout << "Drops due to hard mark not in expected range, should be around 138" << std::endl; + exit (-1); + } + else if (st.qLimDrop < 137 || st.qLimDrop > 139) + { + std::cout << "Drops due to queue full not in expected range, should be around 138" << std::endl; + exit (-1); + } + } + else if (aredTest == 2) + { + if (st.unforcedDrop < 6 || st.unforcedDrop > 17) + { + std::cout << "Drops due to prob mark not in expected range, should be around 14" << std::endl; + exit (-1); + } + else if (st.forcedDrop < 122 || st.forcedDrop > 133) + { + std::cout << "Drops due to hard mark not in expected range, should be around 126" << std::endl; + exit (-1); + } + else if (st.qLimDrop < 122 || st.qLimDrop > 133) + { + std::cout << "Drops due to queue full not in expected range, should be around 126" << std::endl; + exit (-1); + } + } + else if (aredTest == 6) + { + if (st.unforcedDrop < 32 || st.unforcedDrop > 56) + { + std::cout << "Drops due to prob mark not in expected range, should be around 48" << std::endl; + exit (-1); + } + else if (st.forcedDrop < 185 || st.forcedDrop > 202) + { + std::cout << "Drops due to hard mark not in expected range, should be around 201" << std::endl; + exit (-1); + } + else if (st.qLimDrop != 0) + { + std::cout << "There should be no drops due to queue full" << std::endl; + exit (-1); + } + } + else if (aredTest == 7) + { + if (st.unforcedDrop < 76 || st.unforcedDrop > 119) + { + std::cout << "Number of drops due to prob mark is not in expected range, should be around 110" << std::endl; + exit (-1); + } + else if (st.forcedDrop < 133 || st.forcedDrop > 138) + { + std::cout << "Number of drops due to hard mark is not in expected range, should be around 137" << std::endl; + exit (-1); + } + else if (st.qLimDrop != 0) + { + std::cout << "There should be no drops due to queue full" << std::endl; + exit (-1); + } + } + else if (aredTest == 8) + { + if (st.unforcedDrop < 32 || st.unforcedDrop > 56) + { + std::cout << "Number of drops due to prob mark is not in expected range, should be around 48" << std::endl; + exit (-1); + } + else if (st.forcedDrop < 185 || st.forcedDrop > 202) + { + std::cout << "Drops due to hard mark not in expected range, should be around 201" << std::endl; + exit (-1); + } + else if (st.qLimDrop != 0) + { + std::cout << "There should be no drops due to queue full" << std::endl; + exit (-1); + } + } + else if (aredTest == 9) + { + if (st.unforcedDrop < 38 || st.unforcedDrop > 69) + { + std::cout << "Number of drops due to prob mark is not in expected range, should be around 61" << std::endl; + exit (-1); + } + else if (st.forcedDrop < 178 || st.forcedDrop > 191) + { + std::cout << "Number of drops due to hard mark is not in expected range, should be around 187" << std::endl; + exit (-1); + } + else if (st.qLimDrop != 0) + { + std::cout << "There should be no drops due to queue full" << std::endl; + exit (-1); + } + } + else if (aredTest == 10) + { + if (st.unforcedDrop < 82 || st.unforcedDrop > 185) + { + std::cout << "Number of drops due to prob mark is not in expected range, should be around 89" << std::endl; + exit (-1); + } + else if (st.forcedDrop < 129 || st.forcedDrop > 133) + { + std::cout << "Number of drops due to hard mark is not in expected range, should be around 129" << std::endl; + exit (-1); + } + else if (st.qLimDrop != 0) + { + std::cout << "There should be no drops due to queue full" << std::endl; + exit (-1); + } + } + else if (aredTest == 12) + { + if (st.unforcedDrop < 162 || st.unforcedDrop > 204) + { + std::cout << "Number of drops due to prob mark is not in expected range, should be around 181" << std::endl; + exit (-1); + } + else if (st.forcedDrop > 43) + { + std::cout << "Number of drops due to hard mark is not in expected range, should be around 12" << std::endl; + exit (-1); + } + else if (st.qLimDrop != 0) + { + std::cout << "There should be no drops due to queue full" << std::endl; + exit (-1); + } + } + else if (aredTest == 13) + { + if (st.unforcedDrop < 30 || st.unforcedDrop > 49) + { + std::cout << "Number of drops due to prob mark is not in expected range, should be around 36" << std::endl; + exit (-1); + } + else if (st.forcedDrop < 240 || st.forcedDrop > 259) + { + std::cout << "Number of drops due to hard mark is not in expected range, should be around 253" << std::endl; + exit (-1); + } + else if (st.qLimDrop < 12 || st.qLimDrop > 31) + { + std::cout << "Number of drops due to queue full is not in expected range, should be around 25" << std::endl; + exit (-1); + } + } + else if (aredTest == 14) + { + if (st.unforcedDrop < 83 || st.unforcedDrop > 90) + { + std::cout << "Number of drops due to prob mark is not in expected range, should be around 88" << std::endl; + exit (-1); + } + else if (st.forcedDrop < 127 || st.forcedDrop > 132) + { + std::cout << "Number of drops due to hard mark is not in expected range, should be around 129" << std::endl; + exit (-1); + } + else if (st.qLimDrop != 0) + { + std::cout << "There should be no drops due to queue full" << std::endl; + exit (-1); + } + } + else if (aredTest == 15) + { + if (st.unforcedDrop < 83 || st.unforcedDrop > 90) + { + std::cout << "Number of drops due to prob mark is not in expected range, should be around 88" << std::endl; + exit (-1); + } + else if (st.forcedDrop < 127 || st.forcedDrop > 132) + { + std::cout << "Number of drops due to hard mark is not in expected range, should be around 129" << std::endl; + exit (-1); + } + else if (st.qLimDrop != 0) + { + std::cout << "There should be no drops due to queue full" << std::endl; + exit (-1); + } + } + + if (flowMonitor) + { + std::stringstream stmp; + stmp << pathOut << "/ared.flowmon"; + + flowmon->SerializeToXmlFile (stmp.str ().c_str (), false, false); + } + + if (printAredStats) + { + std::cout << "*** ARED stats from Node 2 queue ***" << std::endl; + std::cout << "\t " << st.unforcedDrop << " drops due to prob mark" << std::endl; + std::cout << "\t " << st.forcedDrop << " drops due to hard mark" << std::endl; + std::cout << "\t " << st.qLimDrop << " drops due to queue full" << std::endl; + } + + Simulator::Destroy (); + + return 0; +} diff --git a/src/traffic-control/examples/red-vs-ared.cc b/src/traffic-control/examples/red-vs-ared.cc new file mode 100644 index 000000000..f87635fc0 --- /dev/null +++ b/src/traffic-control/examples/red-vs-ared.cc @@ -0,0 +1,244 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2015 NITK Surathkal + * + * 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: Mohit P. Tahiliani + * + */ + +#include "ns3/core-module.h" +#include "ns3/network-module.h" +#include "ns3/internet-module.h" +#include "ns3/point-to-point-module.h" +#include "ns3/applications-module.h" +#include "ns3/point-to-point-layout-module.h" +#include "ns3/traffic-control-module.h" + +#include +#include +#include + +using namespace ns3; + +int main (int argc, char *argv[]) +{ + uint32_t nLeaf = 10; + uint32_t maxPackets = 100; + bool modeBytes = false; + uint32_t queueDiscLimitPackets = 1000; + double minTh = 5; + double maxTh = 15; + uint32_t pktSize = 512; + std::string appDataRate = "10Mbps"; + std::string queueDiscType = "RED"; + uint16_t port = 5001; + std::string bottleNeckLinkBw = "1Mbps"; + std::string bottleNeckLinkDelay = "50ms"; + + CommandLine cmd; + cmd.AddValue ("nLeaf", "Number of left and right side leaf nodes", nLeaf); + cmd.AddValue ("maxPackets","Max Packets allowed in the device queue", maxPackets); + cmd.AddValue ("queueDiscLimitPackets","Max Packets allowed in the queue disc", queueDiscLimitPackets); + cmd.AddValue ("queueDiscType", "Set Queue disc type to RED or ARED", queueDiscType); + cmd.AddValue ("appPktSize", "Set OnOff App Packet Size", pktSize); + cmd.AddValue ("appDataRate", "Set OnOff App DataRate", appDataRate); + cmd.AddValue ("modeBytes", "Set Queue disc mode to Packets or bytes ", modeBytes); + + cmd.AddValue ("redMinTh", "RED queue minimum threshold", minTh); + cmd.AddValue ("redMaxTh", "RED queue maximum threshold", maxTh); + cmd.Parse (argc,argv); + + if ((queueDiscType != "RED") && (queueDiscType != "ARED")) + { + std::cout << "Invalid queue disc type: Use --queueDiscType=RED or --queueDiscType=ARED" << std::endl; + exit (1); + } + + Config::SetDefault ("ns3::OnOffApplication::PacketSize", UintegerValue (pktSize)); + Config::SetDefault ("ns3::OnOffApplication::DataRate", StringValue (appDataRate)); + + Config::SetDefault ("ns3::Queue::Mode", StringValue ("QUEUE_MODE_PACKETS")); + Config::SetDefault ("ns3::Queue::MaxPackets", UintegerValue (maxPackets)); + + if (!modeBytes) + { + Config::SetDefault ("ns3::RedQueueDisc::Mode", StringValue ("QUEUE_MODE_PACKETS")); + Config::SetDefault ("ns3::RedQueueDisc::QueueLimit", UintegerValue (queueDiscLimitPackets)); + } + else + { + Config::SetDefault ("ns3::RedQueueDisc::Mode", StringValue ("QUEUE_MODE_BYTES")); + Config::SetDefault ("ns3::RedQueueDisc::QueueLimit", UintegerValue (queueDiscLimitPackets * pktSize)); + minTh *= pktSize; + maxTh *= pktSize; + } + + Config::SetDefault ("ns3::RedQueueDisc::MinTh", DoubleValue (minTh)); + Config::SetDefault ("ns3::RedQueueDisc::MaxTh", DoubleValue (maxTh)); + Config::SetDefault ("ns3::RedQueueDisc::LinkBandwidth", StringValue (bottleNeckLinkBw)); + Config::SetDefault ("ns3::RedQueueDisc::LinkDelay", StringValue (bottleNeckLinkDelay)); + Config::SetDefault ("ns3::RedQueueDisc::MeanPktSize", UintegerValue (pktSize)); + + if (queueDiscType == "ARED") + { + // Turn on ARED + Config::SetDefault ("ns3::RedQueueDisc::ARED", BooleanValue (true)); + Config::SetDefault ("ns3::RedQueueDisc::LInterm", DoubleValue (10.0)); + } + + // Create the point-to-point link helpers + PointToPointHelper bottleNeckLink; + bottleNeckLink.SetDeviceAttribute ("DataRate", StringValue (bottleNeckLinkBw)); + bottleNeckLink.SetChannelAttribute ("Delay", StringValue (bottleNeckLinkDelay)); + + PointToPointHelper pointToPointLeaf; + pointToPointLeaf.SetDeviceAttribute ("DataRate", StringValue ("10Mbps")); + pointToPointLeaf.SetChannelAttribute ("Delay", StringValue ("1ms")); + + PointToPointDumbbellHelper d (nLeaf, pointToPointLeaf, + nLeaf, pointToPointLeaf, + bottleNeckLink); + + // Install Stack + InternetStackHelper stack; + for (uint32_t i = 0; i < d.LeftCount (); ++i) + { + stack.Install (d.GetLeft (i)); + } + for (uint32_t i = 0; i < d.RightCount (); ++i) + { + stack.Install (d.GetRight (i)); + } + + stack.Install (d.GetLeft ()); + stack.Install (d.GetRight ()); + TrafficControlHelper tchBottleneck; + tchBottleneck.SetRootQueueDisc ("ns3::RedQueueDisc"); + tchBottleneck.Install (d.GetLeft ()->GetDevice (0)); + tchBottleneck.Install (d.GetRight ()->GetDevice (0)); + + // Assign IP Addresses + d.AssignIpv4Addresses (Ipv4AddressHelper ("10.1.1.0", "255.255.255.0"), + Ipv4AddressHelper ("10.2.1.0", "255.255.255.0"), + Ipv4AddressHelper ("10.3.1.0", "255.255.255.0")); + + // Install on/off app on all right side nodes + OnOffHelper clientHelper ("ns3::TcpSocketFactory", Address ()); + clientHelper.SetAttribute ("OnTime", StringValue ("ns3::UniformRandomVariable[Min=0.,Max=1.]")); + clientHelper.SetAttribute ("OffTime", StringValue ("ns3::UniformRandomVariable[Min=0.,Max=1.]")); + Address sinkLocalAddress (InetSocketAddress (Ipv4Address::GetAny (), port)); + PacketSinkHelper packetSinkHelper ("ns3::TcpSocketFactory", sinkLocalAddress); + ApplicationContainer sinkApps; + for (uint32_t i = 0; i < d.LeftCount (); ++i) + { + sinkApps.Add (packetSinkHelper.Install (d.GetLeft (i))); + } + sinkApps.Start (Seconds (0.0)); + sinkApps.Stop (Seconds (30.0)); + + ApplicationContainer clientApps; + for (uint32_t i = 0; i < d.RightCount (); ++i) + { + // Create an on/off app sending packets to the left side + AddressValue remoteAddress (InetSocketAddress (d.GetLeftIpv4Address (i), port)); + clientHelper.SetAttribute ("Remote", remoteAddress); + clientApps.Add (clientHelper.Install (d.GetRight (i))); + } + clientApps.Start (Seconds (1.0)); // Start 1 second after sink + clientApps.Stop (Seconds (15.0)); // Stop before the sink + + Ipv4GlobalRoutingHelper::PopulateRoutingTables (); + + std::cout << "Running the simulation" << std::endl; + Simulator::Run (); + + uint32_t totalRxBytesCounter = 0; + for (uint32_t i = 0; i < sinkApps.GetN (); i++) + { + Ptr app = sinkApps.Get (i); + Ptr pktSink = DynamicCast (app); + totalRxBytesCounter += pktSink->GetTotalRx (); + } + + if (queueDiscType == "RED") + { + if (modeBytes) + { + if (totalRxBytesCounter > 2772992) + { + std::cout << "RED Goodput is too high, should be about 10403.2 Bytes/sec" << std::endl; + exit (-1); + } + else if (totalRxBytesCounter < 2661888) + { + std::cout << "RED Goodput is too low, should be about 10403.2 Bytes/sec" << std::endl; + exit (-1); + } + } + else + { + if (totalRxBytesCounter > 2759680) + { + std::cout << "RED Goodput is too high, should be about 10355.1 Bytes/sec" << std::endl; + exit (-1); + } + else if (totalRxBytesCounter < 2666496) + { + std::cout << "RED Goodput is too low, should be about 10355.1 Bytes/sec" << std::endl; + exit (-1); + } + } + } + else if (queueDiscType == "ARED") + { + if (modeBytes) + { + if (totalRxBytesCounter > 2771968) + { + std::cout << "ARED Goodput is too high, should be about 10366.7 Bytes/sec" << std::endl; + exit (-1); + } + else if (totalRxBytesCounter < 2654208) + { + std::cout << "ARED Goodput is too low, should be about 10366.7 Bytes/sec" << std::endl; + exit (-1); + } + } + else + { + if (totalRxBytesCounter > 2765824) + { + std::cout << "ARED Goodput is too high, should be about 10317.4 Bytes/sec" << std::endl; + exit (-1); + } + else if (totalRxBytesCounter < 2636800) + { + std::cout << "ARED Goodput is too low, should be about 10317.4 Bytes/sec" << std::endl; + exit (-1); + } + } + } + + std::cout << "----------------------------\nQueue disc Type:" + << queueDiscType + << "\nGoodput Bytes/sec:" + << totalRxBytesCounter / Simulator::Now ().GetSeconds () << std::endl; + std::cout << "----------------------------" << std::endl; + std::cout << "Destroying the simulation" << std::endl; + + Simulator::Destroy (); + return 0; +} diff --git a/src/traffic-control/examples/wscript b/src/traffic-control/examples/wscript index c2c31363b..d5091adf4 100644 --- a/src/traffic-control/examples/wscript +++ b/src/traffic-control/examples/wscript @@ -6,6 +6,12 @@ def build(bld): obj = bld.create_ns3_program('red-tests', ['point-to-point', 'internet', 'applications', 'flow-monitor', 'traffic-control']) obj.source = 'red-tests.cc' + obj = bld.create_ns3_program('red-vs-ared', ['point-to-point', 'point-to-point-layout', 'internet', 'applications', 'traffic-control']) + obj.source = 'red-vs-ared.cc' + + obj = bld.create_ns3_program('adaptive-red-tests', ['point-to-point', 'internet', 'applications', 'flow-monitor', 'traffic-control']) + obj.source = 'adaptive-red-tests.cc' + obj = bld.create_ns3_program('pfifo-vs-red', ['point-to-point', 'point-to-point-layout', 'internet', 'applications', 'traffic-control']) obj.source = 'pfifo-vs-red.cc' diff --git a/src/traffic-control/test/adaptive-red-queue-disc-test-suite.cc b/src/traffic-control/test/adaptive-red-queue-disc-test-suite.cc new file mode 100644 index 000000000..3f78b02a3 --- /dev/null +++ b/src/traffic-control/test/adaptive-red-queue-disc-test-suite.cc @@ -0,0 +1,492 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2015 NITK Surathkal + * + * 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: Mohit P. Tahiliani (tahiliani@nitk.edu.in) + * + */ + +#include "ns3/test.h" +#include "ns3/red-queue-disc.h" +#include "ns3/drop-tail-queue.h" +#include "ns3/uinteger.h" +#include "ns3/string.h" +#include "ns3/double.h" +#include "ns3/log.h" +#include "ns3/simulator.h" +#include "ns3/ipv4-queue-disc-item.h" + +#include "ns3/core-module.h" +#include "ns3/network-module.h" +#include "ns3/internet-module.h" +#include "ns3/point-to-point-module.h" +#include "ns3/applications-module.h" +#include "ns3/point-to-point-layout-module.h" +#include "ns3/traffic-control-module.h" + +using namespace ns3; + +// Tests to verify the working of *automatically set* parameters in ARED +class AutoRedQueueDiscTestCase : public TestCase +{ +public: + AutoRedQueueDiscTestCase (); + virtual void DoRun (void); +private: + void Enqueue (Ptr queue, uint32_t size, uint32_t nPkt); + void RunAutoRedDiscTest (StringValue mode); +}; + +AutoRedQueueDiscTestCase::AutoRedQueueDiscTestCase () + : TestCase ("Sanity check on automatically set parameters of ARED") +{ +} + +void +AutoRedQueueDiscTestCase::RunAutoRedDiscTest (StringValue mode) +{ + uint32_t pktSize = 0; + uint32_t modeSize = 1; // 1 for packets; pktSize for bytes + Ptr queue = CreateObject (); + + NS_TEST_EXPECT_MSG_EQ (queue->SetAttributeFailSafe ("Mode", mode), true, + "Verify that we can actually set the attribute Mode"); + + Ipv4Header ipHeader; + Address dest; + + if (queue->GetMode () == Queue::QUEUE_MODE_BYTES) + { + pktSize = 500; + modeSize = pktSize + ipHeader.GetSerializedSize (); + } + + double minTh = 70 * modeSize; + double maxTh = 150 * modeSize; + uint32_t qSize = 300 * modeSize; + + // test 1: Verify automatic setting of QW. [QW = 0.0 with default LinkBandwidth] + NS_TEST_EXPECT_MSG_EQ (queue->SetAttributeFailSafe ("Mode", mode), true, + "Verify that we can actually set the attribute Mode"); + NS_TEST_EXPECT_MSG_EQ (queue->SetAttributeFailSafe ("MinTh", DoubleValue (minTh)), true, + "Verify that we can actually set the attribute MinTh"); + NS_TEST_EXPECT_MSG_EQ (queue->SetAttributeFailSafe ("MaxTh", DoubleValue (maxTh)), true, + "Verify that we can actually set the attribute MaxTh"); + NS_TEST_EXPECT_MSG_EQ (queue->SetAttributeFailSafe ("QueueLimit", UintegerValue (qSize)), true, + "Verify that we can actually set the attribute QueueLimit"); + NS_TEST_EXPECT_MSG_EQ (queue->SetAttributeFailSafe ("QW", DoubleValue (0.0)), true, + "Verify that we can actually set the attribute QW"); + queue->Initialize (); + Enqueue (queue, pktSize, 300); + RedQueueDisc::Stats st = StaticCast (queue)->GetStats (); + if (queue->GetMode () == Queue::QUEUE_MODE_PACKETS) + { + NS_TEST_EXPECT_MSG_EQ (st.unforcedDrop, 0, "There should be zero dropped packets due to probability mark"); + NS_TEST_EXPECT_MSG_EQ (st.forcedDrop, 0, "There should be zero dropped packets due to hard mark"); + NS_TEST_EXPECT_MSG_EQ (st.qLimDrop, 0, "There should be zero dropped packets due to queue full"); + } + else if (queue->GetMode () == Queue::QUEUE_MODE_BYTES) + { + NS_TEST_EXPECT_MSG_EQ (st.unforcedDrop, 0, "There should be zero dropped packets due to probability mark"); + NS_TEST_EXPECT_MSG_EQ (st.forcedDrop, 0, "There should be zero dropped packets due to hard mark"); + NS_TEST_EXPECT_MSG_EQ (st.qLimDrop, 0, "There should be zero dropped packets due to queue full"); + } + + + // test 2: Verify automatic setting of QW. [QW = 0.0 with lesser LinkBandwidth] + queue = CreateObject (); + NS_TEST_EXPECT_MSG_EQ (queue->SetAttributeFailSafe ("Mode", mode), true, + "Verify that we can actually set the attribute Mode"); + NS_TEST_EXPECT_MSG_EQ (queue->SetAttributeFailSafe ("MinTh", DoubleValue (minTh)), true, + "Verify that we can actually set the attribute MinTh"); + NS_TEST_EXPECT_MSG_EQ (queue->SetAttributeFailSafe ("MaxTh", DoubleValue (maxTh)), true, + "Verify that we can actually set the attribute MaxTh"); + NS_TEST_EXPECT_MSG_EQ (queue->SetAttributeFailSafe ("QueueLimit", UintegerValue (qSize)), true, + "Verify that we can actually set the attribute QueueLimit"); + NS_TEST_EXPECT_MSG_EQ (queue->SetAttributeFailSafe ("QW", DoubleValue (0.0)), true, + "Verify that we can actually set the attribute QW"); + NS_TEST_EXPECT_MSG_EQ (queue->SetAttributeFailSafe ("LinkBandwidth", DataRateValue (DataRate ("0.015Mbps"))), true, + "Verify that we can actually set the attribute LinkBandwidth"); + queue->Initialize (); + Enqueue (queue, pktSize, 300); + st = StaticCast (queue)->GetStats (); + if (queue->GetMode () == Queue::QUEUE_MODE_PACKETS) + { + NS_TEST_EXPECT_MSG_EQ (st.unforcedDrop, 44, "There should be 44 dropped packets due to probability mark"); + NS_TEST_EXPECT_MSG_EQ (st.forcedDrop, 0, "There should be zero dropped packets due to hard mark"); + NS_TEST_EXPECT_MSG_EQ (st.qLimDrop, 0, "There should be zero dropped packets due to queue full"); + } + else if (queue->GetMode () == Queue::QUEUE_MODE_BYTES) + { + NS_TEST_EXPECT_MSG_EQ (st.unforcedDrop, 45, "There should be 45 dropped packets due to probability mark"); + NS_TEST_EXPECT_MSG_EQ (st.forcedDrop, 0, "There should be zero dropped packets due to hard mark"); + NS_TEST_EXPECT_MSG_EQ (st.qLimDrop, 0, "There should be zero dropped packets due to queue full"); + } + + + // test 3: Verify automatic setting of QW. [QW = -1.0 with default LinkBandwidth] + queue = CreateObject (); + NS_TEST_EXPECT_MSG_EQ (queue->SetAttributeFailSafe ("Mode", mode), true, + "Verify that we can actually set the attribute Mode"); + NS_TEST_EXPECT_MSG_EQ (queue->SetAttributeFailSafe ("MinTh", DoubleValue (minTh)), true, + "Verify that we can actually set the attribute MinTh"); + NS_TEST_EXPECT_MSG_EQ (queue->SetAttributeFailSafe ("MaxTh", DoubleValue (maxTh)), true, + "Verify that we can actually set the attribute MaxTh"); + NS_TEST_EXPECT_MSG_EQ (queue->SetAttributeFailSafe ("QueueLimit", UintegerValue (qSize)), true, + "Verify that we can actually set the attribute QueueLimit"); + NS_TEST_EXPECT_MSG_EQ (queue->SetAttributeFailSafe ("QW", DoubleValue (-1.0)), true, + "Verify that we can actually set the attribute QW"); + queue->Initialize (); + Enqueue (queue, pktSize, 300); + st = StaticCast (queue)->GetStats (); + if (queue->GetMode () == Queue::QUEUE_MODE_PACKETS) + { + NS_TEST_EXPECT_MSG_EQ (st.unforcedDrop, 0, "There should be zero dropped packets due to probability mark"); + NS_TEST_EXPECT_MSG_EQ (st.forcedDrop, 0, "There should be zero dropped packets due to hard mark"); + NS_TEST_EXPECT_MSG_EQ (st.qLimDrop, 0, "There should be zero dropped packets due to queue full"); + } + else if (queue->GetMode () == Queue::QUEUE_MODE_BYTES) + { + NS_TEST_EXPECT_MSG_EQ (st.unforcedDrop, 0, "There should be zero dropped packets due to probability mark"); + NS_TEST_EXPECT_MSG_EQ (st.forcedDrop, 0, "There should be zero dropped packets due to hard mark"); + NS_TEST_EXPECT_MSG_EQ (st.qLimDrop, 0, "There should be zero dropped packets due to queue full"); + } + + + // test 4: Verify automatic setting of QW. [QW = -1.0 with lesser LinkBandwidth] + queue = CreateObject (); + NS_TEST_EXPECT_MSG_EQ (queue->SetAttributeFailSafe ("Mode", mode), true, + "Verify that we can actually set the attribute Mode"); + NS_TEST_EXPECT_MSG_EQ (queue->SetAttributeFailSafe ("MinTh", DoubleValue (minTh)), true, + "Verify that we can actually set the attribute MinTh"); + NS_TEST_EXPECT_MSG_EQ (queue->SetAttributeFailSafe ("MaxTh", DoubleValue (maxTh)), true, + "Verify that we can actually set the attribute MaxTh"); + NS_TEST_EXPECT_MSG_EQ (queue->SetAttributeFailSafe ("QueueLimit", UintegerValue (qSize)), true, + "Verify that we can actually set the attribute QueueLimit"); + NS_TEST_EXPECT_MSG_EQ (queue->SetAttributeFailSafe ("QW", DoubleValue (-1.0)), true, + "Verify that we can actually set the attribute QW"); + NS_TEST_EXPECT_MSG_EQ (queue->SetAttributeFailSafe ("LinkBandwidth", DataRateValue (DataRate ("0.015Mbps"))), true, + "Verify that we can actually set the attribute LinkBandwidth"); + queue->Initialize (); + Enqueue (queue, pktSize, 300); + st = StaticCast (queue)->GetStats (); + if (queue->GetMode () == Queue::QUEUE_MODE_PACKETS) + { + NS_TEST_EXPECT_MSG_EQ (st.unforcedDrop, 32, "There should be 32 dropped packets due to probability mark"); + NS_TEST_EXPECT_MSG_EQ (st.forcedDrop, 0, "There should be zero dropped packets due to hard mark"); + NS_TEST_EXPECT_MSG_EQ (st.qLimDrop, 0, "There should be zero dropped packets due to queue full"); + } + else if (queue->GetMode () == Queue::QUEUE_MODE_BYTES) + { + NS_TEST_EXPECT_MSG_EQ (st.unforcedDrop, 33, "There should be 33 dropped packets due to probability mark"); + NS_TEST_EXPECT_MSG_EQ (st.forcedDrop, 0, "There should be zero dropped packets due to hard mark"); + NS_TEST_EXPECT_MSG_EQ (st.qLimDrop, 0, "There should be zero dropped packets due to queue full"); + } + + + // test 5: Verify automatic setting of QW. [QW = -2.0 with default LinkBandwidth] + queue = CreateObject (); + NS_TEST_EXPECT_MSG_EQ (queue->SetAttributeFailSafe ("Mode", mode), true, + "Verify that we can actually set the attribute Mode"); + NS_TEST_EXPECT_MSG_EQ (queue->SetAttributeFailSafe ("MinTh", DoubleValue (minTh)), true, + "Verify that we can actually set the attribute MinTh"); + NS_TEST_EXPECT_MSG_EQ (queue->SetAttributeFailSafe ("MaxTh", DoubleValue (maxTh)), true, + "Verify that we can actually set the attribute MaxTh"); + NS_TEST_EXPECT_MSG_EQ (queue->SetAttributeFailSafe ("QueueLimit", UintegerValue (qSize)), true, + "Verify that we can actually set the attribute QueueLimit"); + NS_TEST_EXPECT_MSG_EQ (queue->SetAttributeFailSafe ("QW", DoubleValue (-2.0)), true, + "Verify that we can actually set the attribute QW"); + queue->Initialize (); + Enqueue (queue, pktSize, 300); + st = StaticCast (queue)->GetStats (); + if (queue->GetMode () == Queue::QUEUE_MODE_PACKETS) + { + NS_TEST_EXPECT_MSG_EQ (st.unforcedDrop, 29, "There should be 29 dropped packets due to probability mark"); + NS_TEST_EXPECT_MSG_EQ (st.forcedDrop, 0, "There should be zero dropped packets due to hard mark"); + NS_TEST_EXPECT_MSG_EQ (st.qLimDrop, 0, "There should be zero dropped packets due to queue full"); + } + else if (queue->GetMode () == Queue::QUEUE_MODE_BYTES) + { + NS_TEST_EXPECT_MSG_EQ (st.unforcedDrop, 30, "There should be 30 dropped packets due to probability mark"); + NS_TEST_EXPECT_MSG_EQ (st.forcedDrop, 0, "There should be zero dropped packets due to hard mark"); + NS_TEST_EXPECT_MSG_EQ (st.qLimDrop, 0, "There should be zero dropped packets due to queue full"); + } + + + // test 6: Verify automatic setting of QW. [QW = -2.0 with lesser LinkBandwidth] + queue = CreateObject (); + NS_TEST_EXPECT_MSG_EQ (queue->SetAttributeFailSafe ("Mode", mode), true, + "Verify that we can actually set the attribute Mode"); + NS_TEST_EXPECT_MSG_EQ (queue->SetAttributeFailSafe ("MinTh", DoubleValue (minTh)), true, + "Verify that we can actually set the attribute MinTh"); + NS_TEST_EXPECT_MSG_EQ (queue->SetAttributeFailSafe ("MaxTh", DoubleValue (maxTh)), true, + "Verify that we can actually set the attribute MaxTh"); + NS_TEST_EXPECT_MSG_EQ (queue->SetAttributeFailSafe ("QueueLimit", UintegerValue (qSize)), true, + "Verify that we can actually set the attribute QueueLimit"); + NS_TEST_EXPECT_MSG_EQ (queue->SetAttributeFailSafe ("QW", DoubleValue (-2.0)), true, + "Verify that we can actually set the attribute QW"); + NS_TEST_EXPECT_MSG_EQ (queue->SetAttributeFailSafe ("LinkBandwidth", DataRateValue (DataRate ("0.015Mbps"))), true, + "Verify that we can actually set the attribute LinkBandwidth"); + queue->Initialize (); + Enqueue (queue, pktSize, 300); + st = StaticCast (queue)->GetStats (); + if (queue->GetMode () == Queue::QUEUE_MODE_PACKETS) + { + NS_TEST_EXPECT_MSG_EQ (st.unforcedDrop, 44, "There should be 44 dropped packets due to probability mark"); + NS_TEST_EXPECT_MSG_EQ (st.forcedDrop, 0, "There should be zero dropped packets due to hard mark"); + NS_TEST_EXPECT_MSG_EQ (st.qLimDrop, 0, "There should be zero dropped packets due to queue full"); + } + else if (queue->GetMode () == Queue::QUEUE_MODE_BYTES) + { + NS_TEST_EXPECT_MSG_EQ (st.unforcedDrop, 46, "There should be 46 dropped packets due to probability mark"); + NS_TEST_EXPECT_MSG_EQ (st.forcedDrop, 0, "There should be zero dropped packets due to hard mark"); + NS_TEST_EXPECT_MSG_EQ (st.qLimDrop, 0, "There should be zero dropped packets due to queue full"); + } + + + // test 7: Verify automatic setting of minTh and maxTh. [minTh = maxTh = 0.0, with default LinkBandwidth] + queue = CreateObject (); + NS_TEST_EXPECT_MSG_EQ (queue->SetAttributeFailSafe ("Mode", mode), true, + "Verify that we can actually set the attribute Mode"); + NS_TEST_EXPECT_MSG_EQ (queue->SetAttributeFailSafe ("MinTh", DoubleValue (0.0)), true, + "Verify that we can actually set the attribute MinTh"); + NS_TEST_EXPECT_MSG_EQ (queue->SetAttributeFailSafe ("MaxTh", DoubleValue (0.0)), true, + "Verify that we can actually set the attribute MaxTh"); + NS_TEST_EXPECT_MSG_EQ (queue->SetAttributeFailSafe ("QueueLimit", UintegerValue (qSize)), true, + "Verify that we can actually set the attribute QueueLimit"); + if (queue->GetMode () == Queue::QUEUE_MODE_BYTES) + { + NS_TEST_EXPECT_MSG_EQ (queue->SetAttributeFailSafe ("MeanPktSize", UintegerValue (modeSize)), true, + "Verify that we can actually set the attribute MeanPktSize"); + } + queue->Initialize (); + Enqueue (queue, pktSize, 300); + st = StaticCast (queue)->GetStats (); + if (queue->GetMode () == Queue::QUEUE_MODE_PACKETS) + { + NS_TEST_EXPECT_MSG_EQ (st.unforcedDrop, 20, "There should be 20 dropped packets due to probability mark"); + NS_TEST_EXPECT_MSG_EQ (st.forcedDrop, 113, "There should be 113 dropped packets due to hard mark"); + NS_TEST_EXPECT_MSG_EQ (st.qLimDrop, 0, "There should be zero dropped packets due to queue full"); + } + else if (queue->GetMode () == Queue::QUEUE_MODE_BYTES) + { + NS_TEST_EXPECT_MSG_EQ (st.unforcedDrop, 21, "There should be 21 dropped packets due to probability mark"); + NS_TEST_EXPECT_MSG_EQ (st.forcedDrop, 113, "There should be 113 dropped packets due to hard mark"); + NS_TEST_EXPECT_MSG_EQ (st.qLimDrop, 0, "There should be zero dropped packets due to queue full"); + } + + + // test 8: Verify automatic setting of minTh and maxTh. [minTh = maxTh = 0.0, with higher LinkBandwidth] + queue = CreateObject (); + NS_TEST_EXPECT_MSG_EQ (queue->SetAttributeFailSafe ("Mode", mode), true, + "Verify that we can actually set the attribute Mode"); + NS_TEST_EXPECT_MSG_EQ (queue->SetAttributeFailSafe ("MinTh", DoubleValue (0.0)), true, + "Verify that we can actually set the attribute MinTh"); + NS_TEST_EXPECT_MSG_EQ (queue->SetAttributeFailSafe ("MaxTh", DoubleValue (0.0)), true, + "Verify that we can actually set the attribute MaxTh"); + NS_TEST_EXPECT_MSG_EQ (queue->SetAttributeFailSafe ("QueueLimit", UintegerValue (qSize)), true, + "Verify that we can actually set the attribute QueueLimit"); + NS_TEST_EXPECT_MSG_EQ (queue->SetAttributeFailSafe ("LinkBandwidth", DataRateValue (DataRate ("150Mbps"))), true, + "Verify that we can actually set the attribute LinkBandwidth"); + if (queue->GetMode () == Queue::QUEUE_MODE_BYTES) + { + NS_TEST_EXPECT_MSG_EQ (queue->SetAttributeFailSafe ("MeanPktSize", UintegerValue (modeSize)), true, + "Verify that we can actually set the attribute MeanPktSize"); + } + queue->Initialize (); + Enqueue (queue, pktSize, 300); + st = StaticCast (queue)->GetStats (); + if (queue->GetMode () == Queue::QUEUE_MODE_PACKETS) + { + NS_TEST_EXPECT_MSG_EQ (st.unforcedDrop, 0, "There should be zero dropped packets due to probability mark"); + NS_TEST_EXPECT_MSG_EQ (st.forcedDrop, 0, "There should be zero dropped packets due to hard mark"); + NS_TEST_EXPECT_MSG_EQ (st.qLimDrop, 0, "There should be zero dropped packets due to queue full"); + } + else if (queue->GetMode () == Queue::QUEUE_MODE_BYTES) + { + NS_TEST_EXPECT_MSG_EQ (st.unforcedDrop, 0, "There should be zero dropped packets due to probability mark"); + NS_TEST_EXPECT_MSG_EQ (st.forcedDrop, 0, "There should be zero dropped packets due to hard mark"); + NS_TEST_EXPECT_MSG_EQ (st.qLimDrop, 0, "There should be zero dropped packets due to queue full"); + } +} + +void +AutoRedQueueDiscTestCase::Enqueue (Ptr queue, uint32_t size, uint32_t nPkt) +{ + Ipv4Header ipHeader; + Address dest; + for (uint32_t i = 0; i < nPkt; i++) + { + queue->Enqueue (Create (Create (size), dest, 0, ipHeader)); + } +} + +void +AutoRedQueueDiscTestCase::DoRun (void) +{ + RunAutoRedDiscTest (StringValue ("QUEUE_MODE_PACKETS")); + RunAutoRedDiscTest (StringValue ("QUEUE_MODE_BYTES")); + Simulator::Destroy (); +} + + +// Tests to verify the working of *adaptive* parameter in ARED +class AdaptiveRedQueueDiscTestCase : public TestCase +{ +public: + AdaptiveRedQueueDiscTestCase (); + virtual void DoRun (void); +private: + void RunAdaptiveRedDiscTest (StringValue mode); +}; + +AdaptiveRedQueueDiscTestCase::AdaptiveRedQueueDiscTestCase () + : TestCase ("Sanity check on adaptive parameter of ARED") +{ +} + +void +AdaptiveRedQueueDiscTestCase::RunAdaptiveRedDiscTest (StringValue mode) +{ + uint32_t pktSize = 500; + uint32_t modeSize = 1; // 1 for packets; pktSize for bytes + uint32_t nLeaf = 3; + + Config::SetDefault ("ns3::OnOffApplication::PacketSize", UintegerValue (pktSize)); + Config::SetDefault ("ns3::OnOffApplication::DataRate", StringValue ("10Mbps")); + + Ptr queue = CreateObject (); + + NS_TEST_EXPECT_MSG_EQ (queue->SetAttributeFailSafe ("Mode", mode), true, + "Verify that we can actually set the attribute Mode"); + + Ipv4Header ipHeader; + + if (queue->GetMode () == Queue::QUEUE_MODE_BYTES) + { + modeSize = pktSize + ipHeader.GetSerializedSize (); + } + + uint32_t qSize = 100 * modeSize; + + Config::SetDefault ("ns3::RedQueueDisc::ARED", BooleanValue (true)); + Config::SetDefault ("ns3::RedQueueDisc::LInterm", DoubleValue (10.0)); + Config::SetDefault ("ns3::RedQueueDisc::QueueLimit", UintegerValue (qSize)); + Config::SetDefault ("ns3::RedQueueDisc::MeanPktSize", UintegerValue (pktSize + ipHeader.GetSerializedSize ())); + + // Create the point-to-point link helpers + PointToPointHelper bottleNeckLink; + bottleNeckLink.SetDeviceAttribute ("DataRate", StringValue ("1.5Mbps")); + bottleNeckLink.SetChannelAttribute ("Delay", StringValue ("20ms")); + + PointToPointHelper pointToPointLeaf; + pointToPointLeaf.SetDeviceAttribute ("DataRate", StringValue ("10Mbps")); + pointToPointLeaf.SetChannelAttribute ("Delay", StringValue ("1ms")); + + PointToPointDumbbellHelper d (nLeaf, pointToPointLeaf, + nLeaf, pointToPointLeaf, + bottleNeckLink); + + // Install Stack + InternetStackHelper stack; + for (uint32_t i = 0; i < d.LeftCount (); ++i) + { + stack.Install (d.GetLeft (i)); + } + for (uint32_t i = 0; i < d.RightCount (); ++i) + { + stack.Install (d.GetRight (i)); + } + + stack.Install (d.GetLeft ()); + stack.Install (d.GetRight ()); + TrafficControlHelper tchBottleneck; + tchBottleneck.SetRootQueueDisc ("ns3::RedQueueDisc"); + tchBottleneck.Install (d.GetLeft ()->GetDevice (0)); + tchBottleneck.Install (d.GetRight ()->GetDevice (0)); + + // Assign IP Addresses + d.AssignIpv4Addresses (Ipv4AddressHelper ("10.1.1.0", "255.255.255.0"), + Ipv4AddressHelper ("10.2.1.0", "255.255.255.0"), + Ipv4AddressHelper ("10.3.1.0", "255.255.255.0")); + + // Install on/off app on all right side nodes + OnOffHelper clientHelper ("ns3::TcpSocketFactory", Address ()); + clientHelper.SetAttribute ("OnTime", StringValue ("ns3::UniformRandomVariable[Min=0.,Max=1.]")); + clientHelper.SetAttribute ("OffTime", StringValue ("ns3::UniformRandomVariable[Min=0.,Max=1.]")); + Address sinkLocalAddress (InetSocketAddress (Ipv4Address::GetAny (), 5001)); + PacketSinkHelper packetSinkHelper ("ns3::TcpSocketFactory", sinkLocalAddress); + ApplicationContainer sinkApps; + for (uint32_t i = 0; i < d.LeftCount (); ++i) + { + sinkApps.Add (packetSinkHelper.Install (d.GetLeft (i))); + } + sinkApps.Start (Seconds (0.0)); + sinkApps.Stop (Seconds (30.0)); + + ApplicationContainer clientApps; + for (uint32_t i = 0; i < d.RightCount (); ++i) + { + // Create an on/off app sending packets to the left side + AddressValue remoteAddress (InetSocketAddress (d.GetLeftIpv4Address (i), 5001)); + clientHelper.SetAttribute ("Remote", remoteAddress); + clientApps.Add (clientHelper.Install (d.GetRight (i))); + } + clientApps.Start (Seconds (1.0)); // Start 1 second after sink + clientApps.Stop (Seconds (15.0)); // Stop before the sink + + Ipv4GlobalRoutingHelper::PopulateRoutingTables (); + + Simulator::Run (); + + uint32_t totalRxBytesCounter = 0; + for (uint32_t i = 0; i < sinkApps.GetN (); i++) + { + Ptr app = sinkApps.Get (i); + Ptr pktSink = DynamicCast (app); + totalRxBytesCounter += pktSink->GetTotalRx (); + } + + if (queue->GetMode () == Queue::QUEUE_MODE_PACKETS) + { + NS_TEST_EXPECT_MSG_EQ (totalRxBytesCounter, 2605000, "Total received bytes should be 2605000"); + } + else if (queue->GetMode () == Queue::QUEUE_MODE_BYTES) + { + NS_TEST_EXPECT_MSG_EQ (totalRxBytesCounter, 2557000, "Total received bytes should be 2557000"); + } + + Simulator::Destroy (); +} + +void +AdaptiveRedQueueDiscTestCase::DoRun (void) +{ + RunAdaptiveRedDiscTest (StringValue ("QUEUE_MODE_PACKETS")); + RunAdaptiveRedDiscTest (StringValue ("QUEUE_MODE_BYTES")); + Simulator::Destroy (); +} + +static class AredQueueDiscTestSuite : public TestSuite +{ +public: + AredQueueDiscTestSuite () + : TestSuite ("adaptive-red-queue-disc", UNIT) + { + AddTestCase (new AutoRedQueueDiscTestCase (), TestCase::QUICK); // Tests for automatically set parameters of ARED + AddTestCase (new AdaptiveRedQueueDiscTestCase (), TestCase::QUICK); // Tests for adaptive parameter of ARED + } +} g_aredQueueDiscTestSuite; diff --git a/src/traffic-control/wscript b/src/traffic-control/wscript index 67ca264ec..e48d7b40a 100644 --- a/src/traffic-control/wscript +++ b/src/traffic-control/wscript @@ -24,6 +24,7 @@ def build(bld): 'test/pfifo-fast-queue-disc-test-suite.cc', 'test/red-queue-disc-test-suite.cc', 'test/codel-queue-disc-test-suite.cc', + 'test/adaptive-red-queue-disc-test-suite.cc', ] headers = bld(features='ns3header')