traffic-control: Add Nonlinear RED

This commit is contained in:
Nichit Bodhak Goel
2017-05-28 10:21:43 +02:00
parent 2732d27e75
commit 4ff9a97d0c
6 changed files with 288 additions and 0 deletions

View File

@@ -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 <phanikiran.harithas@gmail.com>
* Nichit Bodhak Goel <nichit93@gmail.com>
* Mohit P. Tahiliani <tahiliani@nitk.edu.in>
*
*/
#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 <iostream>
#include <iomanip>
#include <map>
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 <false> or bytes <true>", 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<RedQueueDisc> (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;
}

View File

@@ -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'

View File

@@ -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
**********

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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<RedQueueDisc> (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<RedQueueDisc> ();
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<RedQueueDisc> (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<RedQueueDisc> ();
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<RedQueueDisc> (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