From 4ff9a97d0c7044106ad56ba896b82b4a96c9bf81 Mon Sep 17 00:00:00 2001 From: Nichit Bodhak Goel Date: Sun, 28 May 2017 10:21:43 +0200 Subject: [PATCH] traffic-control: Add Nonlinear RED --- examples/traffic-control/red-vs-nlred.cc | 192 ++++++++++++++++++ examples/traffic-control/wscript | 3 + src/traffic-control/doc/red.rst | 26 +++ src/traffic-control/model/red-queue-disc.cc | 11 + src/traffic-control/model/red-queue-disc.h | 1 + .../test/red-queue-disc-test-suite.cc | 55 +++++ 6 files changed, 288 insertions(+) create mode 100644 examples/traffic-control/red-vs-nlred.cc diff --git a/examples/traffic-control/red-vs-nlred.cc b/examples/traffic-control/red-vs-nlred.cc new file mode 100644 index 000000000..6cf3c122b --- /dev/null +++ b/examples/traffic-control/red-vs-nlred.cc @@ -0,0 +1,192 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2016 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 + * + * Authors: Phani Kiran S V S + * Nichit Bodhak Goel + * 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 NLRED", 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 != "NLRED")) + { + std::cout << "Invalid queue disc type: Use --queueDiscType=RED or --queueDiscType=NLRED" << std::endl; + exit (1); + } + + Config::SetDefault ("ns3::OnOffApplication::PacketSize", UintegerValue (pktSize)); + Config::SetDefault ("ns3::OnOffApplication::DataRate", StringValue (appDataRate)); + + Config::SetDefault ("ns3::QueueBase::Mode", StringValue ("QUEUE_MODE_PACKETS")); + Config::SetDefault ("ns3::QueueBase::MaxPackets", UintegerValue (maxPackets)); + + if (!modeBytes) + { + Config::SetDefault ("ns3::RedQueueDisc::Mode", StringValue ("QUEUE_DISC_MODE_PACKETS")); + Config::SetDefault ("ns3::RedQueueDisc::QueueLimit", UintegerValue (queueDiscLimitPackets)); + } + else + { + Config::SetDefault ("ns3::RedQueueDisc::Mode", StringValue ("QUEUE_DISC_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 == "NLRED") + { + // Turn on NLRED + Config::SetDefault ("ns3::RedQueueDisc::NLRED", BooleanValue (true)); + } + + // 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; + QueueDiscContainer queueDiscs; + tchBottleneck.SetRootQueueDisc ("ns3::RedQueueDisc"); + tchBottleneck.Install (d.GetLeft ()->GetDevice (0)); + queueDiscs = 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 (); + + RedQueueDisc::Stats st = StaticCast (queueDiscs.Get (0))->GetStats (); + + if (st.unforcedDrop == 0) + { + std::cout << "There should be some unforced drops" << std::endl; + exit (1); + } + + if (st.qLimDrop != 0) + { + std::cout << "There should be zero drops due to queue full" << std::endl; + exit (1); + } + + std::cout << "*** Stats from the bottleneck queue disc ***" << 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; + std::cout << "Destroying the simulation" << std::endl; + + Simulator::Destroy (); + return 0; +} diff --git a/examples/traffic-control/wscript b/examples/traffic-control/wscript index 1204d8b63..a05df8b21 100644 --- a/examples/traffic-control/wscript +++ b/examples/traffic-control/wscript @@ -11,3 +11,6 @@ def build(bld): obj = bld.create_ns3_program('red-vs-fengadaptive', ['point-to-point', 'point-to-point-layout', 'internet', 'applications', 'traffic-control']) obj.source = 'red-vs-fengadaptive.cc' + + obj = bld.create_ns3_program('red-vs-nlred', ['point-to-point', 'point-to-point-layout', 'internet', 'applications', 'traffic-control']) + obj.source = 'red-vs-nlred.cc' diff --git a/src/traffic-control/doc/red.rst b/src/traffic-control/doc/red.rst index cd3359467..d066c937d 100644 --- a/src/traffic-control/doc/red.rst +++ b/src/traffic-control/doc/red.rst @@ -41,6 +41,12 @@ Feng's Adaptive RED is a variant of RED that adapts the maximum drop probability. The model in ns-3 contains implementation of this feature, and is a port of ns-2 Feng's Adaptive RED model. +Nonlinear Random Early Detection (NLRED) +======================================== +NLRED is a variant of RED in which the linear packet dropping function of +RED is replaced by a nonlinear quadratic function. This approach makes packet +dropping gentler for light traffic load and aggressive for heavy traffic load. + Explicit Congestion Notification (ECN) ====================================== This RED model supports an ECN mode of operation to notify endpoints of @@ -73,6 +79,9 @@ Feng's Adaptive RED queue implementation is based on the algorithm provided in: W. C. Feng et al, http://ieeexplore.ieee.org/stamp/stamp.jsp?arnumber=752150 +NLRED queue implementation is based on the algorithm provided in: +Kaiyu Zhou et al, http://www.sciencedirect.com/science/article/pii/S1389128606000879 + The addition of explicit congestion notification (ECN) to IP: K. K. Ramakrishnan et al, https://tools.ietf.org/html/rfc3168 @@ -117,6 +126,10 @@ attributes: * FengAlpha (increment parameter for m_curMaxP, Default: 3) * FengBeta (decrement parameter for m_curMaxP, Default: 2) +The following attribute should be turned on to simulate NLRED queue disc: + +* NLRED (Boolean attribute. Default: false) + Consult the ns-3 documentation for explanation of these attributes. Simulating ARED @@ -161,6 +174,16 @@ set to true, as done in ``examples/traffic-control/red-vs-fengadaptive.cc``: Config::SetDefault ("ns3::RedQueueDisc::FengAdaptive", BooleanValue (true)); +Simulating NLRED +================ + +To switch on NLRED algorithm, the attribute NLRED must be set to true, +as shown below: + +.. sourcecode:: cpp + +Config::SetDefault ("ns3::RedQueueDisc::NLRED", BooleanValue (true)); + Examples ======== @@ -173,6 +196,9 @@ ARED queue examples can be found at: Feng's Adaptive RED example can be found at: ``examples/traffic-control/red-vs-fengadaptive.cc`` +NLRED queue example can be found at: +``examples/traffic-control/red-vs-nlred.cc`` + Validation ********** diff --git a/src/traffic-control/model/red-queue-disc.cc b/src/traffic-control/model/red-queue-disc.cc index fb1854c47..1807c9fd9 100644 --- a/src/traffic-control/model/red-queue-disc.cc +++ b/src/traffic-control/model/red-queue-disc.cc @@ -119,6 +119,11 @@ TypeId RedQueueDisc::GetTypeId (void) BooleanValue (false), MakeBooleanAccessor (&RedQueueDisc::m_isFengAdaptive), MakeBooleanChecker ()) + .AddAttribute ("NLRED", + "True to enable Nonlinear RED", + BooleanValue (false), + MakeBooleanAccessor (&RedQueueDisc::m_isNonlinear), + MakeBooleanChecker ()) .AddAttribute ("MinTh", "Minimum average length threshold in packets/bytes", DoubleValue (5), @@ -792,6 +797,12 @@ RedQueueDisc::CalculatePNew (double qAvg, double maxTh, bool isGentle, double vA * th_min to th_max */ p = vA * qAvg + vB; + + if (m_isNonlinear) + { + p *= p * 1.5; + } + p *= maxP; } diff --git a/src/traffic-control/model/red-queue-disc.h b/src/traffic-control/model/red-queue-disc.h index e147ad374..c6c213e71 100644 --- a/src/traffic-control/model/red-queue-disc.h +++ b/src/traffic-control/model/red-queue-disc.h @@ -346,6 +346,7 @@ private: double m_beta; //!< Decrement parameter for m_curMaxP in ARED Time m_rtt; //!< Rtt to be considered while automatically setting m_bottom in ARED bool m_isFengAdaptive; //!< True to enable Feng's Adaptive RED + bool m_isNonlinear; //!< True to enable Nonlinear RED double m_b; //!< Increment parameter for m_curMaxP in Feng's Adaptive RED double m_a; //!< Decrement parameter for m_curMaxP in Feng's Adaptive RED bool m_isNs1Compat; //!< Ns-1 compatibility diff --git a/src/traffic-control/test/red-queue-disc-test-suite.cc b/src/traffic-control/test/red-queue-disc-test-suite.cc index 49bea1c79..d3ebd9b24 100644 --- a/src/traffic-control/test/red-queue-disc-test-suite.cc +++ b/src/traffic-control/test/red-queue-disc-test-suite.cc @@ -239,6 +239,8 @@ RedQueueDiscTestCase::RunRedTest (StringValue mode) uint32_t test7; uint32_t test11; uint32_t test12; + uint32_t test13; + uint32_t test14; } drop; @@ -473,6 +475,59 @@ RedQueueDiscTestCase::RunRedTest (StringValue mode) st = StaticCast (queue)->GetStats (); drop.test12 = st.unforcedDrop; NS_TEST_EXPECT_MSG_LT (drop.test12, drop.test11, "Test 12 should have less drops due to probability mark than test 11"); + + + // test 11: RED with Linear drop probability + queue = CreateObject (); + minTh = 30 * modeSize; + maxTh = 90 * modeSize; + 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.002)), true, + "Verify that we can actually set the attribute QW"); + NS_TEST_EXPECT_MSG_EQ (queue->SetAttributeFailSafe ("LInterm", DoubleValue (2)), true, + "Verify that we can actually set the attribute LInterm"); + NS_TEST_EXPECT_MSG_EQ (queue->SetAttributeFailSafe ("Gentle", BooleanValue (true)), true, + "Verify that we can actually set the attribute Gentle"); + queue->Initialize (); + Enqueue (queue, pktSize, 300, false); + st = StaticCast (queue)->GetStats (); + drop.test13 = st.unforcedDrop; + NS_TEST_EXPECT_MSG_NE (drop.test13, 0, "There should some dropped packets due to probability mark"); + + + // test 14: RED with Nonlinear drop probability + queue = CreateObject (); + minTh = 30 * modeSize; + maxTh = 90 * modeSize; + 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.002)), true, + "Verify that we can actually set the attribute QW"); + NS_TEST_EXPECT_MSG_EQ (queue->SetAttributeFailSafe ("LInterm", DoubleValue (2)), true, + "Verify that we can actually set the attribute LInterm"); + NS_TEST_EXPECT_MSG_EQ (queue->SetAttributeFailSafe ("Gentle", BooleanValue (true)), true, + "Verify that we can actually set the attribute Gentle"); + NS_TEST_EXPECT_MSG_EQ (queue->SetAttributeFailSafe ("NLRED", BooleanValue (true)), true, + "Verify that we can actually set the attribute NLRED"); + queue->Initialize (); + Enqueue (queue, pktSize, 300, false); + st = StaticCast (queue)->GetStats (); + drop.test14 = st.unforcedDrop; + NS_TEST_EXPECT_MSG_LT (drop.test14, drop.test13, "Test 14 should have less drops due to probability mark than test 13"); + } void