traffic-control: Add token bucket filter

This commit is contained in:
Surya Seetharaman
2018-03-03 10:55:17 +01:00
parent 2005953337
commit 68979374fb
8 changed files with 1291 additions and 0 deletions

View File

@@ -58,6 +58,7 @@ us a note on ns-developers mailing list.</p>
<li> Ipv[4,6]AddressGenerator can now check if an address is allocated (<b>Ipv[4,6]AddressGenerator::IsAddressAllocated</b>) or a network has some allocated address (<b>Ipv[4,6]AddressGenerator::IsNetworkAllocated</b>).</li>
<li> LTE UEs can now use IPv6 to send and receive traffic.</li>
<li> UAN module now supports IP stack.</li>
<li> Added a FIFO queue disc (FifoQueueDisc) and the Token Bucket Filter (TbfQueueDisc).</li>
</ul>
<h2>Changes to existing API:</h2>
<ul>

View File

@@ -0,0 +1,149 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2015 Universita' degli Studi di Napoli "Federico II"
* 2017 Kungliga Tekniska Högskolan
*
* 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: Pasquale Imputato <p.imputato@gmail.com>
* Author: Stefano Avallone <stefano.avallone@unina.it>
* Author: Surya Seetharaman <suryaseetharaman.9@gmail.com> - ported from ns-3
* RedQueueDisc traffic-control example to accommodate TbfQueueDisc example.
*/
#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/traffic-control-module.h"
// This simple example shows how to use TrafficControlHelper to install a
// QueueDisc on a device.
//
// Network topology
//
// 10.1.1.0
// n0 -------------- n1
// point-to-point
//
// The output will consist of all the traced changes in
// the number of tokens in TBF's first and second buckets:
//
// FirstBucketTokens 0 to x
// SecondBucketTokens 0 to x
// FirstBucketTokens x to 0
// SecondBucketTokens x to 0
//
using namespace ns3;
NS_LOG_COMPONENT_DEFINE ("TbfExample");
void
FirstBucketTokensTrace (uint32_t oldValue, uint32_t newValue)
{
std::cout << "FirstBucketTokens " << oldValue << " to " << newValue << std::endl;
}
void
SecondBucketTokensTrace (uint32_t oldValue, uint32_t newValue)
{
std::cout << "SecondBucketTokens " << oldValue << " to " << newValue << std::endl;
}
int
main (int argc, char *argv[])
{
double simulationTime = 10; //seconds
uint32_t burst = 10000;
uint32_t mtu = 0;
DataRate rate = DataRate ("1Mbps");
DataRate peakRate = DataRate ("0bps");
CommandLine cmd;
cmd.AddValue ("burst", "Size of first bucket in bytes", burst);
cmd.AddValue ("mtu", "Size of second bucket in bytes", mtu);
cmd.AddValue ("rate", "Rate of tokens arriving in first bucket", rate);
cmd.AddValue ("peakRate", "Rate of tokens arriving in second bucket", peakRate);
cmd.Parse (argc, argv);
NodeContainer nodes;
nodes.Create (2);
PointToPointHelper pointToPoint;
pointToPoint.SetDeviceAttribute ("DataRate", StringValue ("2Mb/s"));
pointToPoint.SetChannelAttribute ("Delay", StringValue ("0ms"));
NetDeviceContainer devices;
devices = pointToPoint.Install (nodes);
InternetStackHelper stack;
stack.Install (nodes);
TrafficControlHelper tch;
tch.SetRootQueueDisc ("ns3::TbfQueueDisc",
"Burst", UintegerValue (burst),
"Mtu", UintegerValue (mtu),
"Rate", DataRateValue (DataRate (rate)),
"PeakRate", DataRateValue (DataRate (peakRate)));
QueueDiscContainer qdiscs = tch.Install (devices);
Ptr<QueueDisc> q = qdiscs.Get (1);
q->TraceConnectWithoutContext ("TokensInFirstBucket", MakeCallback (&FirstBucketTokensTrace));
q->TraceConnectWithoutContext ("TokensInSecondBucket", MakeCallback (&SecondBucketTokensTrace));
Ipv4AddressHelper address;
address.SetBase ("10.1.1.0", "255.255.255.0");
Ipv4InterfaceContainer interfaces = address.Assign (devices);
//Flow
uint16_t port = 7;
Address localAddress (InetSocketAddress (Ipv4Address::GetAny (), port));
PacketSinkHelper packetSinkHelper ("ns3::TcpSocketFactory", localAddress);
ApplicationContainer sinkApp = packetSinkHelper.Install (nodes.Get (0));
sinkApp.Start (Seconds (0.0));
sinkApp.Stop (Seconds (simulationTime + 0.1));
uint32_t payloadSize = 1448;
Config::SetDefault ("ns3::TcpSocket::SegmentSize", UintegerValue (payloadSize));
OnOffHelper onoff ("ns3::TcpSocketFactory", Ipv4Address::GetAny ());
onoff.SetAttribute ("OnTime", StringValue ("ns3::ConstantRandomVariable[Constant=1]"));
onoff.SetAttribute ("OffTime", StringValue ("ns3::ConstantRandomVariable[Constant=0.2]"));
onoff.SetAttribute ("PacketSize", UintegerValue (payloadSize));
onoff.SetAttribute ("DataRate", StringValue ("1.1Mb/s")); //bit/s
ApplicationContainer apps;
InetSocketAddress rmt (interfaces.GetAddress (0), port);
rmt.SetTos (0xb8);
AddressValue remoteAddress (rmt);
onoff.SetAttribute ("Remote", remoteAddress);
apps.Add (onoff.Install (nodes.Get (1)));
apps.Start (Seconds (1.0));
apps.Stop (Seconds (simulationTime + 0.1));
Simulator::Stop (Seconds (simulationTime + 5));
Simulator::Run ();
Simulator::Destroy ();
std::cout << std::endl << "*** TC Layer statistics ***" << std::endl;
std::cout << q->GetStats () << std::endl;
return 0;
}

View File

@@ -14,3 +14,7 @@ def build(bld):
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'
obj = bld.create_ns3_program('tbf-example',
['internet', 'point-to-point', 'applications', 'traffic-control'])
obj.source = 'tbf-example.cc'

View File

@@ -0,0 +1,142 @@
.. include:: replace.txt
.. highlight:: cpp
TBF queue disc
----------------
This chapter describes the TBF ([Ref1]_) queue disc implementation
in |ns3|. The TBF model in ns-3 is ported based on Linux kernel code implemented by
A. Kuznetsov and D. Torokhov.
TBF is a qdisc that allows controlling the bandwidth of the output according
to a set rate with the possibility of managing burst conditions also. The TBF implementation
consists of a bucket (buffer) having a limited capacity into which tokens (normally representing a
unit of bytes or a single packet of predetermined size) are added at a fixed rate 'r' called the
token rate. Whenever a packet arrives into the tx queue (fifo by default), the bucket is checked
to see if there are appropriate number of tokens that is equivalent to the length of the packet in
bytes. If yes, then the tokens are removed and the packet is passed for transmission. If no, then
packets will have to wait until there are sufficient tokens in the bucket. This data conformance
can be thus put into three possible scenarios [Ref3]_:
1. Data rate = Token rate : Packets pass without delay
2. Data rate < Token rate : Few tokens are depleted.
* Burst Condition : So the tokens might accumulate and the bucket might become
full. Then, the next packets to enter TBF will be transmitted right away without
having any limit applied to them, until the bucket is empty. This is called a burst
condition and in TBF the burst parameter defines the size of the bucket. In order
to overcome this problem and provide better control over the bursts, TBF
implements a second bucket which is smaller and generally the same size as the
MTU. This second bucket cannot store large amount of tokens, but its
replenishing rate will be a lot faster than the one of the big bucket. This second
rate is called 'peakRate' and it will determine the maximum rate of a burst.
3. Data rate > Token rate : This causes the TBF algorithm to throttle itself for a while as
soon as the bucket gets empty. This is called an 'overlimit situation' [Ref2]_. In this situation,
some of the packets will be blocked until enough tokens are available at which time a schedule for
the waking of the queue will be done. If packets keep coming in, at a larger rate, then the
packets will start to get dropped when the total number of bytes exceeds the QueueLimit.
Model Description
*****************
The TBF queue disc does not require packet filters, does not admit internal queues
and uses a single child queue disc. If the user does not provide a child queue disc,
a Fifo queue disc operating in the same mode (packet or byte) as the TBF queue disc
and having a size equal to the TBF QueueLimit attribute is created. Otherwise, the
capacity of the TBF queue disc is determined by the capacity of the child queue disc.
There are two token buckets: first bucket and second bucket. The size of the
first bucket called 'Burst' should always be greater than the size of the second
bucket called the Mtu (which is usually the size of a single packet). But the
'PeakRate' which is the second bucket's token rate should be always greater than
the 'Rate' which is the first bucket's token rate.
If the PeakRate is zero, then the second bucket does not exist. In order to activate
the second bucket, both the Mtu and PeakRate values have to be greater than zero. If
the Mtu value is zero at initialization time, then if a NetDevice exits, the Mtu's
value will be equal to the Mtu of the NetDevice. But if no NetDevice exists, then
the QueueDisc will complain thus prompting the user to set the Mtu value.
The source code for the TBF model is located in the directory ``src/traffic-control/model``
and consists of 2 files `tbf-queue-disc.h` and `tbf-queue-disc.cc` defining a TbfQueueDisc
class.
* class :cpp:class:`TbfQueueDisc`: This class implements the main TBF algorithm:
* ``TbfQueueDisc::DoEnqueue ()``: This routine enqueue's the incoming packet if the queue is not full and drops the packet otherwise.
* ``TbfQueueDisc::DoPeek ()``: This routine peeks for the top item in the queue and if the queue is not empty, it returns the topmost item.
* ``TbfQueueDisc::DoDequeue ()``: This routine performs the dequeuing of packets according to the following logic:
* It calls ``TbfQueueDisc::Peek ()`` and calculates the size of the packet to be dequeued in bytes.
* Then it calculates the time difference 'delta', which is the time elapsed since the last update of tokens in the buckets.
* If the second bucket exists, the number of tokens are updated according to the 'PeakRate' and 'delta'.
* From this second bucket a number of tokens equal to the size of the packet to be dequeued is subtracted.
* Now the number of tokens in the first bucket are updated according to 'Rate' and 'delta'.
* From this first bucket a number of tokens equal to the size of the packet to be dequeued is subtracted.
* If after this, both the first and second buckets have tokens greater than zero, then the packet is dequeued.
* Else, an event to ``QueueDisc::Run ()`` is scheduled after a time period when enough tokens will be present for the dequeue operation.
References
==========
.. [Ref1] A. Kuznetsov and D. Torokhov; Linux Cross Reference Source Code; Available online at `<http://lxr.free-electrons.com/source/net/sched/sch_tbf.c>`_.
.. [Ref2] J. Vehent; Journey to the Center of the Linux Kernel: Traffic Control, Shaping and QoS; Available online at `<http://wiki.linuxwall.info/doku.php/en:ressources:dossiers:networking:traffic_control#tbf\_-_token_bucket_filter>`_.
.. [Ref3] Practical IP Network QoS: TBF queuing discipline; Available online at `<http://web.opalsoft.net/qos/default.php?p=ds-24>`_.
Attributes
==========
The key attributes that the TbfQueueDisc class holds include the following:
* ``MaxSize:`` The maximum number of packets/bytes the queue disc can hold. The default value is 1000 packets.
* ``Burst:`` Size of the first bucket, in bytes. The default value is 125000 bytes.
* ``Mtu:`` Size of second bucket defaults to the MTU of the attached NetDevice, if any, or 0 otherwise.
* ``Rate:`` Rate at which tokens enter the first bucket. The default value is 125KB/s.
* ``PeakRate:`` Rate at which tokens enter the second bucket. The default value is 0KB/s, which means that there is no second bucket.
TraceSources
============
The TbfQueueDisc class provides the following trace sources:
* ``TokensInFirstBucket:`` Number of First Bucket Tokens in bytes
* ``TokensInSecondBucket:`` Number of Second Bucket Tokens in bytes
Examples
========
The example for TBF is `tbf-example.cc` located in ``examples/traffic-control/``. The command to run the file (the invocation below shows the available command-line options) is:
::
$ ./waf --run "tbf-example --PrintHelp"
$ ./waf --run "tbf-example --burst=125000 --rate=1Mbps --peakRate=1.5Mbps"
The expected output from the previous commands are traced value changes in the number of tokens in the first and second buckets.
Validation
**********
The TBF model is tested using :cpp:class:`TbfQueueDiscTestSuite` class defined in `src/traffic-control/test/tbf-queue-disc-test-suite.cc`. The suite includes 4 test cases:
* Test 1: Simple Enqueue/Dequeue with verification of attribute setting and subtraction of tokens from the buckets.
* Test 2: When DataRate == FirstBucketTokenRate; packets should pass smoothly.
* Test 3: When DataRate >>> FirstBucketTokenRate; some packets should get blocked and waking of queue should get scheduled.
* Test 4: When DataRate < FirstBucketTokenRate; burst condition, peakRate is set so that bursts are controlled.
The test suite can be run using the following commands:
::
$ ./waf configure --enable-examples --enable-tests
$ ./waf build
$ ./test.py -s tbf-queue-disc
or
::
$ NS_LOG="TbfQueueDisc" ./waf --run "test-runner --suite=tbf-queue-disc"

View File

@@ -0,0 +1,369 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2017 Kungliga Tekniska Högskolan
* 2017 Universita' degli Studi di Napoli Federico II
*
* 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
*
* TBF, The Token Bucket Filter Queueing discipline
*
* This implementation is based on linux kernel code by
* Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
* Dmitry Torokhov <dtor@mail.ru> - allow attaching inner qdiscs -
* original idea by Martin Devera
*
* Implemented in ns-3 by: Surya Seetharaman <suryaseetharaman.9@gmail.com>
* Stefano Avallone <stavallo@unina.it>
*/
#include "ns3/log.h"
#include "ns3/enum.h"
#include "ns3/simulator.h"
#include "ns3/uinteger.h"
#include "ns3/attribute.h"
#include "ns3/object-factory.h"
#include "ns3/drop-tail-queue.h"
#include "ns3/net-device-queue-interface.h"
#include "tbf-queue-disc.h"
namespace ns3 {
NS_LOG_COMPONENT_DEFINE ("TbfQueueDisc");
NS_OBJECT_ENSURE_REGISTERED (TbfQueueDisc);
TypeId TbfQueueDisc::GetTypeId (void)
{
static TypeId tid = TypeId ("ns3::TbfQueueDisc")
.SetParent<QueueDisc> ()
.SetGroupName ("TrafficControl")
.AddConstructor<TbfQueueDisc> ()
.AddAttribute ("MaxSize",
"The max queue size",
QueueSizeValue (QueueSize ("1000p")),
MakeQueueSizeAccessor (&QueueDisc::SetMaxSize,
&QueueDisc::GetMaxSize),
MakeQueueSizeChecker ())
.AddAttribute ("Burst",
"Size of the first bucket in bytes",
UintegerValue (125000),
MakeUintegerAccessor (&TbfQueueDisc::SetBurst),
MakeUintegerChecker<uint32_t> ())
.AddAttribute ("Mtu",
"Size of the second bucket in bytes. If null, it is initialized"
" to the MTU of the attached NetDevice (if any)",
UintegerValue (0),
MakeUintegerAccessor (&TbfQueueDisc::SetMtu),
MakeUintegerChecker<uint32_t> ())
.AddAttribute ("Rate",
"Rate at which tokens enter the first bucket in bps or Bps.",
DataRateValue (DataRate ("125KB/s")),
MakeDataRateAccessor (&TbfQueueDisc::SetRate),
MakeDataRateChecker ())
.AddAttribute ("PeakRate",
"Rate at which tokens enter the second bucket in bps or Bps."
"If null, there is no second bucket",
DataRateValue (DataRate ("0KB/s")),
MakeDataRateAccessor (&TbfQueueDisc::SetPeakRate),
MakeDataRateChecker ())
.AddTraceSource ("TokensInFirstBucket",
"Number of First Bucket Tokens in bytes",
MakeTraceSourceAccessor (&TbfQueueDisc::m_btokens),
"ns3::TracedValueCallback::Uint32")
.AddTraceSource ("TokensInSecondBucket",
"Number of Second Bucket Tokens in bytes",
MakeTraceSourceAccessor (&TbfQueueDisc::m_ptokens),
"ns3::TracedValueCallback::Uint32")
;
return tid;
}
TbfQueueDisc::TbfQueueDisc ()
: QueueDisc (QueueDiscSizePolicy::SINGLE_CHILD_QUEUE_DISC)
{
NS_LOG_FUNCTION (this);
}
TbfQueueDisc::~TbfQueueDisc ()
{
NS_LOG_FUNCTION (this);
}
void
TbfQueueDisc::DoDispose (void)
{
NS_LOG_FUNCTION (this);
QueueDisc::DoDispose ();
}
void
TbfQueueDisc::SetBurst (uint32_t burst)
{
NS_LOG_FUNCTION (this << burst);
m_burst = burst;
}
uint32_t
TbfQueueDisc::GetBurst (void) const
{
NS_LOG_FUNCTION (this);
return m_burst;
}
void
TbfQueueDisc::SetMtu (uint32_t mtu)
{
NS_LOG_FUNCTION (this << mtu);
m_mtu = mtu;
}
uint32_t
TbfQueueDisc::GetMtu (void) const
{
NS_LOG_FUNCTION (this);
return m_mtu;
}
void
TbfQueueDisc::SetRate (DataRate rate)
{
NS_LOG_FUNCTION (this << rate);
m_rate = rate;
}
DataRate
TbfQueueDisc::GetRate (void) const
{
NS_LOG_FUNCTION (this);
return m_rate;
}
void
TbfQueueDisc::SetPeakRate (DataRate peakRate)
{
NS_LOG_FUNCTION (this << peakRate);
m_peakRate = peakRate;
}
DataRate
TbfQueueDisc::GetPeakRate (void) const
{
NS_LOG_FUNCTION (this);
return m_peakRate;
}
uint32_t
TbfQueueDisc::GetFirstBucketTokens (void) const
{
NS_LOG_FUNCTION (this);
return m_btokens;
}
uint32_t
TbfQueueDisc::GetSecondBucketTokens (void) const
{
NS_LOG_FUNCTION (this);
return m_ptokens;
}
bool
TbfQueueDisc::DoEnqueue (Ptr<QueueDiscItem> item)
{
NS_LOG_FUNCTION (this << item);
bool retval = GetQueueDiscClass (0)->GetQueueDisc ()->Enqueue (item);
// If Queue::Enqueue fails, QueueDisc::Drop is called by the child queue
// disc because QueueDisc::AddQueueDiscClass sets the drop callback
NS_LOG_LOGIC ("Current queue size: " << GetNPackets () << " packets, " << GetNBytes () << " bytes");
return retval;
}
Ptr<const QueueDiscItem>
TbfQueueDisc::DoPeek ()
{
NS_LOG_FUNCTION (this);
Ptr<const QueueDiscItem> item = PeekDequeued ();
if (!item)
{
NS_LOG_LOGIC ("No packet returned");
return 0;
}
NS_LOG_LOGIC ("Current queue size: " << GetNPackets () << " packets, " << GetNBytes () << " bytes");
return item;
}
Ptr<QueueDiscItem>
TbfQueueDisc::DoDequeue (void)
{
NS_LOG_FUNCTION (this);
Ptr<const QueueDiscItem> itemPeek = GetQueueDiscClass (0)->GetQueueDisc ()->Peek ();
if (itemPeek)
{
uint32_t pktSize = itemPeek->GetSize ();
NS_LOG_LOGIC ("Next packet size " << pktSize);
int64_t btoks = 0;
int64_t ptoks = 0;
Time now = Simulator::Now ();
double delta = (now - m_timeCheckPoint).GetSeconds ();
NS_LOG_LOGIC ("Time Difference delta " << delta);
if (m_peakRate > DataRate ("0bps"))
{
ptoks = m_ptokens + round (delta * (m_peakRate.GetBitRate () / 8));
if (ptoks > m_mtu)
{
ptoks = m_mtu;
}
NS_LOG_LOGIC ("Number of ptokens we can consume " << ptoks);
NS_LOG_LOGIC ("Required to dequeue next packet " << pktSize);
ptoks -= pktSize;
}
btoks = m_btokens + round (delta * (m_rate.GetBitRate () / 8));
if (btoks > m_burst)
{
btoks = m_burst;
}
NS_LOG_LOGIC ("Number of btokens we can consume " << btoks);
NS_LOG_LOGIC ("Required to dequeue next packet " << pktSize);
btoks -= pktSize;
if ((btoks|ptoks) >= 0) // else packet blocked
{
Ptr<QueueDiscItem> item = GetQueueDiscClass (0)->GetQueueDisc ()->DequeuePeeked ();
if (!item)
{
NS_LOG_DEBUG ("That's odd! Expecting the peeked packet, we got no packet.");
return item;
}
m_timeCheckPoint = now;
m_btokens = btoks;
m_ptokens = ptoks;
NS_LOG_LOGIC (m_btokens << " btokens and " << m_ptokens << " ptokens after packet dequeue");
NS_LOG_LOGIC ("Current queue size: " << GetNPackets () << " packets, " << GetNBytes () << " bytes");
return item;
}
// the watchdog timer setup.
/* A packet gets blocked if the above if condition is not satisfied, i.e.
both the ptoks and btoks are less than zero. In that case we have to
schedule the waking of queue when enough tokens are available. */
if (m_id.IsExpired () == true)
{
Time requiredDelayTime = std::max (m_rate.CalculateBytesTxTime (-btoks),
m_peakRate.CalculateBytesTxTime (-ptoks));
m_id = Simulator::Schedule (requiredDelayTime, &QueueDisc::Run, this);
NS_LOG_LOGIC("Waking Event Scheduled in " << requiredDelayTime);
}
}
return 0;
}
bool
TbfQueueDisc::CheckConfig (void)
{
NS_LOG_FUNCTION (this);
if (GetNInternalQueues () > 0)
{
NS_LOG_ERROR ("TbfQueueDisc cannot have internal queues");
return false;
}
if (GetNPacketFilters () > 0)
{
NS_LOG_ERROR ("TbfQueueDisc cannot have packet filters");
return false;
}
if (GetNQueueDiscClasses () == 0)
{
// create a FIFO queue disc
ObjectFactory factory;
factory.SetTypeId ("ns3::FifoQueueDisc");
Ptr<QueueDisc> qd = factory.Create<QueueDisc> ();
if (!qd->SetMaxSize (GetMaxSize ()))
{
NS_LOG_ERROR ("Cannot set the max size of the child queue disc to that of TbfQueueDisc");
return false;
}
qd->Initialize ();
Ptr<QueueDiscClass> c = CreateObject<QueueDiscClass> ();
c->SetQueueDisc (qd);
AddQueueDiscClass (c);
}
if (GetNQueueDiscClasses () != 1)
{
NS_LOG_ERROR ("TbfQueueDisc needs 1 child queue disc");
return false;
}
if (m_mtu == 0 && GetNetDevice ())
{
m_mtu = GetNetDevice ()->GetMtu ();
}
if (m_mtu == 0 && m_peakRate > DataRate ("0bps"))
{
NS_LOG_ERROR ("A non-null peak rate has been set, but the mtu is null. No packet will be dequeued");
return false;
}
if (m_burst <= m_mtu)
{
NS_LOG_WARN ("The size of the first bucket (" << m_burst << ") should be "
<< "greater than the size of the second bucket (" << m_mtu << ").");
}
if (m_peakRate > DataRate ("0bps") && m_peakRate <= m_rate)
{
NS_LOG_WARN ("The rate for the second bucket (" << m_peakRate << ") should be "
<< "greater than the rate for the first bucket (" << m_rate << ").");
}
return true;
}
void
TbfQueueDisc::InitializeParams (void)
{
NS_LOG_FUNCTION (this);
// Token Buckets are full at the beginning.
m_btokens = m_burst;
m_ptokens = m_mtu;
// Initialising other variables to 0.
m_timeCheckPoint = Seconds (0);
m_id = EventId ();
}
} // namespace ns3

View File

@@ -0,0 +1,172 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2017 Kungliga Tekniska Högskolan
* 2017 Universita' degli Studi di Napoli Federico II
*
* 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
*
* TBF, The Token Bucket Filter Queueing discipline
*
* This implementation is based on linux kernel code by
* Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
* Dmitry Torokhov <dtor@mail.ru> - allow attaching inner qdiscs -
* original idea by Martin Devera
*
* Implemented in ns-3 by: Surya Seetharaman <suryaseetharaman.9@gmail.com>
* Stefano Avallone <stavallo@unina.it>
*/
#ifndef TBF_QUEUE_DISC_H
#define TBF_QUEUE_DISC_H
#include "ns3/queue-disc.h"
#include "ns3/nstime.h"
#include "ns3/boolean.h"
#include "ns3/data-rate.h"
#include "ns3/random-variable-stream.h"
#include "ns3/traced-value.h"
#include "ns3/trace-source-accessor.h"
#include "ns3/event-id.h"
namespace ns3 {
/**
* \ingroup traffic-control
*
* \brief A TBF packet queue disc
*/
class TbfQueueDisc : public QueueDisc
{
public:
/**
* \brief Get the type ID.
* \return the object TypeId
*/
static TypeId GetTypeId (void);
/**
* \brief TbfQueueDisc Constructor
*
* Create a TBF queue disc
*/
TbfQueueDisc ();
/**
* \brief Destructor
*
* Destructor
*/
virtual ~TbfQueueDisc ();
/**
* \brief Set the size of the first bucket in bytes.
*
* \param burst The size of first bucket in bytes.
*/
void SetBurst (uint32_t burst);
/**
* \brief Get the size of the first bucket in bytes.
*
* \returns The size of the first bucket in bytes.
*/
uint32_t GetBurst (void) const;
/**
* \brief Set the size of the second bucket in bytes.
*
* \param mtu The size of second bucket in bytes.
*/
void SetMtu (uint32_t mtu);
/**
* \brief Get the size of the second bucket in bytes.
*
* \returns The size of the second bucket in bytes.
*/
uint32_t GetMtu (void) const;
/**
* \brief Set the rate of the tokens entering the first bucket.
*
* \param rate The rate of first bucket tokens.
*/
void SetRate (DataRate rate);
/**
* \brief Get the rate of the tokens entering the first bucket.
*
* \returns The rate of first bucket tokens.
*/
DataRate GetRate (void) const;
/**
* \brief Set the rate of the tokens entering the second bucket.
*
* \param peakRate The rate of second bucket tokens.
*/
void SetPeakRate (DataRate peakRate);
/**
* \brief Get the rate of the tokens entering the second bucket.
*
* \returns The rate of second bucket tokens.
*/
DataRate GetPeakRate (void) const;
/**
* \brief Get the current number of tokens inside the first bucket in bytes.
*
* \returns The number of first bucket tokens in bytes.
*/
uint32_t GetFirstBucketTokens (void) const;
/**
* \brief Get the current number of tokens inside the second bucket in bytes.
*
* \returns The number of second bucket tokens in bytes.
*/
uint32_t GetSecondBucketTokens (void) const;
protected:
/**
* \brief Dispose of the object
*/
virtual void DoDispose (void);
private:
virtual bool DoEnqueue (Ptr<QueueDiscItem> item);
virtual Ptr<QueueDiscItem> DoDequeue (void);
virtual Ptr<const QueueDiscItem> DoPeek (void);
virtual bool CheckConfig (void);
virtual void InitializeParams (void);
/* parameters for the TBF Queue Disc */
uint32_t m_burst; //!< Size of first bucket in bytes
uint32_t m_mtu; //!< Size of second bucket in bytes
DataRate m_rate; //!< Rate at which tokens enter the first bucket
DataRate m_peakRate; //!< Rate at which tokens enter the second bucket
/* variables stored by TBF Queue Disc */
TracedValue<uint32_t> m_btokens; //!< Current number of tokens in first bucket
TracedValue<uint32_t> m_ptokens; //!< Current number of tokens in second bucket
Time m_timeCheckPoint; //!< Time check-point
EventId m_id; //!< EventId of the scheduled queue waking event when enough tokens are available
};
} // namespace ns3
#endif /* TBF_QUEUE_DISC_H */

View File

@@ -0,0 +1,451 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2017 Kungliga Tekniska Högskolan
* 2017 Universita' degli Studi di Napoli Federico II
*
* 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: Surya Seetharaman <suryaseetharaman.9@gmail.com>
* Stefano Avallone <stavallo@unina.it>
*/
#include "ns3/test.h"
#include "ns3/tbf-queue-disc.h"
#include "ns3/packet.h"
#include "ns3/uinteger.h"
#include "ns3/string.h"
#include "ns3/double.h"
#include "ns3/log.h"
#include "ns3/simulator.h"
#include "ns3/node-container.h"
#include "ns3/simple-net-device.h"
#include "ns3/simple-channel.h"
#include "ns3/traffic-control-layer.h"
#include "ns3/config.h"
using namespace ns3;
/**
* \ingroup traffic-control-test
* \ingroup tests
*
* \brief Tbf Queue Disc Test Item
*/
class TbfQueueDiscTestItem : public QueueDiscItem {
public:
/**
* Constructor
*
* \param p the packet
* \param addr the address
*/
TbfQueueDiscTestItem (Ptr<Packet> p, const Address & addr);
virtual ~TbfQueueDiscTestItem ();
virtual void AddHeader (void);
virtual bool Mark (void);
private:
TbfQueueDiscTestItem ();
/**
* \brief Copy constructor
* Disable default implementation to avoid misuse
*/
TbfQueueDiscTestItem (const TbfQueueDiscTestItem &);
/**
* \brief Assignment operator
* \return this object
* Disable default implementation to avoid misuse
*/
TbfQueueDiscTestItem &operator = (const TbfQueueDiscTestItem &);
};
TbfQueueDiscTestItem::TbfQueueDiscTestItem (Ptr<Packet> p, const Address & addr)
: QueueDiscItem (p, addr, 0)
{
}
TbfQueueDiscTestItem::~TbfQueueDiscTestItem ()
{
}
void
TbfQueueDiscTestItem::AddHeader (void)
{
}
bool
TbfQueueDiscTestItem::Mark (void)
{
return false;
}
/**
* \ingroup traffic-control-test
* \ingroup tests
*
* \brief Tbf Queue Disc Test Case
*/
class TbfQueueDiscTestCase : public TestCase
{
public:
TbfQueueDiscTestCase ();
virtual void DoRun (void);
private:
/**
* Enqueue function
* \param queue the queue disc into which enqueue needs to be done
* \param dest the destination address
* \param size the size of the packet in bytes to be enqueued
*/
void Enqueue (Ptr<TbfQueueDisc> queue, Address dest, uint32_t size);
/**
* DequeueAndCheck function to check if a packet is blocked or not after dequeuing and verify against expected result
* \param queue the queue disc on which DequeueAndCheck needs to be done
* \param flag the boolean value against which the return value of dequeue () has to be compared with
* \param printStatement the string to be printed in the NS_TEST_EXPECT_MSG_EQ
*/
void DequeueAndCheck (Ptr<TbfQueueDisc> queue, bool flag, std::string printStatement);
/**
* Run TBF test function
* \param mode the mode
*/
void RunTbfTest (QueueSizeUnit mode);
};
TbfQueueDiscTestCase::TbfQueueDiscTestCase ()
: TestCase ("Sanity check on the TBF queue implementation")
{
}
void
TbfQueueDiscTestCase::RunTbfTest (QueueSizeUnit mode)
{
uint32_t pktSize = 1500;
// 1 for packets; pktSize for bytes
uint32_t modeSize = 1;
uint32_t qSize = 4;
uint32_t burst = 6000;
uint32_t mtu = 0;
DataRate rate = DataRate ("6KB/s");
DataRate peakRate = DataRate ("0KB/s");
Ptr<TbfQueueDisc> queue = CreateObject<TbfQueueDisc> ();
// test 1: Simple Enqueue/Dequeue with verification of attribute setting
/* 1. There is no second bucket since "peakRate" is set to 0.
2. A simple enqueue of five packets, each containing 1500B is followed by
the dequeue those five packets.
3. The subtraction of tokens from the first bucket to send out each of the
five packets is monitored and verified.
Note : The number of tokens in the first bucket is full at the beginning.
With the dequeuing of each packet, the number of tokens keeps decreasing.
So packets are dequeued as long as there are enough tokens in the bucket. */
if (mode == QueueSizeUnit::BYTES)
{
modeSize = pktSize;
qSize = qSize * modeSize;
}
NS_TEST_EXPECT_MSG_EQ (queue->SetAttributeFailSafe ("MaxSize", QueueSizeValue (QueueSize (mode, qSize))),
true, "Verify that we can actually set the attribute MaxSize");
NS_TEST_EXPECT_MSG_EQ (queue->SetAttributeFailSafe ("Burst", UintegerValue (burst)), true,
"Verify that we can actually set the attribute Burst");
NS_TEST_EXPECT_MSG_EQ (queue->SetAttributeFailSafe ("Mtu", UintegerValue (mtu)), true,
"Verify that we can actually set the attribute Mtu");
NS_TEST_EXPECT_MSG_EQ (queue->SetAttributeFailSafe ("Rate", DataRateValue (rate)), true,
"Verify that we can actually set the attribute Rate");
NS_TEST_EXPECT_MSG_EQ (queue->SetAttributeFailSafe ("PeakRate", DataRateValue (peakRate)), true,
"Verify that we can actually set the attribute PeakRate");
Address dest;
Ptr<Packet> p1, p2, p3, p4, p5;
p1 = Create<Packet> (pktSize);
p2 = Create<Packet> (pktSize);
p3 = Create<Packet> (pktSize);
p4 = Create<Packet> (pktSize);
p5 = Create<Packet> (pktSize);
queue->Initialize ();
NS_TEST_EXPECT_MSG_EQ (queue->GetCurrentSize ().GetValue (), 0 * modeSize, "There should be no packets in there");
queue->Enqueue (Create<TbfQueueDiscTestItem> (p1, dest));
NS_TEST_EXPECT_MSG_EQ (queue->GetCurrentSize ().GetValue (), 1 * modeSize, "There should be one packet in there");
queue->Enqueue (Create<TbfQueueDiscTestItem> (p2, dest));
NS_TEST_EXPECT_MSG_EQ (queue->GetCurrentSize ().GetValue (), 2 * modeSize, "There should be two packets in there");
queue->Enqueue (Create<TbfQueueDiscTestItem> (p3, dest));
NS_TEST_EXPECT_MSG_EQ (queue->GetCurrentSize ().GetValue (), 3 * modeSize, "There should be three packets in there");
queue->Enqueue (Create<TbfQueueDiscTestItem> (p4, dest));
NS_TEST_EXPECT_MSG_EQ (queue->GetCurrentSize ().GetValue (), 4 * modeSize, "There should be four packets in there");
queue->Enqueue (Create<TbfQueueDiscTestItem> (p5, dest));
NS_TEST_EXPECT_MSG_EQ (queue->GetCurrentSize ().GetValue (), 4 * modeSize,
"There should still be four packets in there as this enqueue cannot happen since QueueLimit will be exceeded");
Ptr<QueueDiscItem> item;
NS_TEST_EXPECT_MSG_EQ (queue->GetFirstBucketTokens (), burst, "The first token bucket should be full");
item = queue->Dequeue ();
NS_TEST_EXPECT_MSG_EQ ((item != 0), true, "I want to remove the first packet");
NS_TEST_EXPECT_MSG_EQ (queue->GetCurrentSize ().GetValue (), 3 * modeSize, "There should be three packets in there");
NS_TEST_EXPECT_MSG_EQ (item->GetPacket ()->GetUid (), p1->GetUid (), "was this the first packet ?");
NS_TEST_EXPECT_MSG_EQ (queue->GetFirstBucketTokens (), burst - (1 * pktSize),
"The number of tokens in the first bucket should be one pktSize lesser");
item = queue->Dequeue ();
NS_TEST_EXPECT_MSG_EQ ((item != 0), true, "I want to remove the second packet");
NS_TEST_EXPECT_MSG_EQ (queue->GetCurrentSize ().GetValue (), 2 * modeSize, "There should be two packets in there");
NS_TEST_EXPECT_MSG_EQ (item->GetPacket ()->GetUid (), p2->GetUid (), "Was this the second packet ?");
NS_TEST_EXPECT_MSG_EQ (queue->GetFirstBucketTokens (), burst - (2 * pktSize),
"The number of tokens in the first bucket should be two pktSizes lesser");
item = queue->Dequeue ();
NS_TEST_EXPECT_MSG_EQ ((item != 0), true, "I want to remove the third packet");
NS_TEST_EXPECT_MSG_EQ (queue->GetCurrentSize ().GetValue (), 1 * modeSize, "There should be one packet in there");
NS_TEST_EXPECT_MSG_EQ (item->GetPacket ()->GetUid (), p3->GetUid (), "Was this the third packet ?");
NS_TEST_EXPECT_MSG_EQ (queue->GetFirstBucketTokens (), burst - (3 * pktSize),
"The number of tokens in the first bucket should be three pktSizes lesser");
item = queue->Dequeue ();
NS_TEST_EXPECT_MSG_EQ ((item != 0), true, "I want to remove the fourth packet");
NS_TEST_EXPECT_MSG_EQ (queue->GetCurrentSize ().GetValue (), 0 * modeSize, "There should be zero packet in there");
NS_TEST_EXPECT_MSG_EQ (item->GetPacket ()->GetUid (), p4->GetUid (), "Was this the fourth packet ?");
NS_TEST_EXPECT_MSG_EQ (queue->GetFirstBucketTokens (), burst - (4 * pktSize),
"The number of tokens in the first bucket should be four pktSizes lesser");
// test 2 : When DataRate == FirstBucketTokenRate; packets should pass smoothly.
queue = CreateObject<TbfQueueDisc> ();
qSize = 10;
pktSize = 1000;
burst = 10000;
mtu = 1000;
rate = DataRate ("10KB/s");
peakRate = DataRate ("100KB/s");
uint32_t nPkt = qSize;
if (mode == QueueSizeUnit::BYTES)
{
modeSize = pktSize;
qSize = qSize * modeSize;
}
NS_TEST_EXPECT_MSG_EQ (queue->SetAttributeFailSafe ("MaxSize", QueueSizeValue (QueueSize (mode, qSize))),
true, "Verify that we can actually set the attribute MaxSize");
NS_TEST_EXPECT_MSG_EQ (queue->SetAttributeFailSafe ("Burst", UintegerValue (burst)), true,
"Verify that we can actually set the attribute Burst");
NS_TEST_EXPECT_MSG_EQ (queue->SetAttributeFailSafe ("Mtu", UintegerValue (mtu)), true,
"Verify that we can actually set the attribute Mtu");
NS_TEST_EXPECT_MSG_EQ (queue->SetAttributeFailSafe ("Rate", DataRateValue (rate)), true,
"Verify that we can actually set the attribute Rate");
NS_TEST_EXPECT_MSG_EQ (queue->SetAttributeFailSafe ("PeakRate", DataRateValue (peakRate)), true,
"Verify that we can actually set the attribute PeakRate");
queue->Initialize ();
double delay = 0.09;
for (uint32_t i = 1; i <= nPkt; i++)
{
Simulator::Schedule (Time (Seconds ((i + 1) * delay)), &TbfQueueDiscTestCase::Enqueue, this, queue, dest, pktSize);
}
delay = 0.1;
for (uint32_t i = 1; i <= nPkt; i++)
{
Simulator::Schedule (Time (Seconds ((i + 1) * delay)), &TbfQueueDiscTestCase::DequeueAndCheck, this,
queue, true, "No packet should be blocked");
}
Simulator::Stop (Seconds (1));
Simulator::Run ();
// test 3 : When DataRate >>> FirstBucketTokenRate; some packets should get blocked and waking of queue should get scheduled.
/* 10 packets are enqueued and then dequeued. Since the token rate is less than the data rate, the last packet i.e the 10th
packet gets blocked and waking of queue is scheduled after a time when enough tokens will be available. At that time the
10th packet passes through. */
queue = CreateObject<TbfQueueDisc> ();
Config::SetDefault ("ns3::QueueDisc::Quota", UintegerValue (1));
NodeContainer nodesA;
nodesA.Create (2);
Ptr<SimpleNetDevice> txDevA = CreateObject<SimpleNetDevice> ();
nodesA.Get (0)->AddDevice (txDevA);
Ptr<SimpleNetDevice> rxDevA = CreateObject<SimpleNetDevice> ();
nodesA.Get (1)->AddDevice (rxDevA);
Ptr<SimpleChannel> channelA = CreateObject<SimpleChannel> ();
txDevA->SetChannel (channelA);
rxDevA->SetChannel (channelA);
txDevA->SetNode (nodesA.Get (0));
rxDevA->SetNode (nodesA.Get (1));
dest = txDevA->GetAddress ();
Ptr<TrafficControlLayer> tcA = CreateObject<TrafficControlLayer> ();
nodesA.Get (0)->AggregateObject (tcA);
queue->SetNetDevice (txDevA);
tcA->SetRootQueueDiscOnDevice (txDevA, queue);
tcA->Initialize ();
burst = 5000;
mtu = 1000;
rate = DataRate ("5KB/s");
peakRate = DataRate ("100KB/s");
if (mode == QueueSizeUnit::BYTES)
{
modeSize = pktSize;
qSize = qSize * modeSize;
}
NS_TEST_EXPECT_MSG_EQ (queue->SetAttributeFailSafe ("MaxSize", QueueSizeValue (QueueSize (mode, qSize))),
true, "Verify that we can actually set the attribute MaxSize");
NS_TEST_EXPECT_MSG_EQ (queue->SetAttributeFailSafe ("Burst", UintegerValue (burst)), true,
"Verify that we can actually set the attribute Burst");
NS_TEST_EXPECT_MSG_EQ (queue->SetAttributeFailSafe ("Mtu", UintegerValue (mtu)), true,
"Verify that we can actually set the attribute Mtu");
NS_TEST_EXPECT_MSG_EQ (queue->SetAttributeFailSafe ("Rate", DataRateValue (rate)), true,
"Verify that we can actually set the attribute Rate");
NS_TEST_EXPECT_MSG_EQ (queue->SetAttributeFailSafe ("PeakRate", DataRateValue (peakRate)), true,
"Verify that we can actually set the attribute PeakRate");
delay = 0.09;
for (uint32_t i = 1; i <= nPkt; i++)
{
Simulator::Schedule (Time (Seconds ((i + 1) * delay)), &TbfQueueDiscTestCase::Enqueue, this, queue, dest, pktSize);
}
delay = 0.1;
for (uint32_t i = 1; i <= nPkt; i++)
{
if (i == 10)
{
Simulator::Schedule (Time (Seconds ((i + 1) * delay)), &TbfQueueDiscTestCase::DequeueAndCheck, this,
queue, false, "10th packet should be blocked");
}
else
{
Simulator::Schedule (Time (Seconds ((i + 1) * delay)), &TbfQueueDiscTestCase::DequeueAndCheck, this,
queue, true, "This packet should not be blocked");
}
}
Simulator::Stop (Seconds (1.3));
Simulator::Run ();
// test 4 : When DataRate < FirstBucketTokenRate; burst condition, peakRate is set so that bursts are controlled.
/* This test checks the burst control ability of TBF. 10 packets each of size 1000 bytes are enqueued followed by
their dequeue. The data rate (25 KB/s) is not sufficiently higher than the btokens rate (15 KB/s), so that in
the startup phase the first bucket is not empty. Hence when adequate tokens are present in the second bucket,
the packets get transmitted, otherwise they are blocked. So basically the transmission of packets falls under the
regulation of the second bucket since first bucket will always have excess tokens. TBF does not let all
the packets go smoothly without any control just because there are excess tokens in the first bucket. */
queue = CreateObject<TbfQueueDisc> ();
Config::SetDefault ("ns3::QueueDisc::Quota", UintegerValue (1));
NodeContainer nodesB;
nodesB.Create (2);
Ptr<SimpleNetDevice> txDevB = CreateObject<SimpleNetDevice> ();
nodesB.Get (0)->AddDevice (txDevB);
Ptr<SimpleNetDevice> rxDevB = CreateObject<SimpleNetDevice> ();
nodesB.Get (1)->AddDevice (rxDevB);
Ptr<SimpleChannel> channelB = CreateObject<SimpleChannel> ();
txDevB->SetChannel (channelB);
rxDevB->SetChannel (channelB);
txDevB->SetNode (nodesB.Get (0));
rxDevB->SetNode (nodesB.Get (1));
dest = txDevB->GetAddress ();
Ptr<TrafficControlLayer> tcB = CreateObject<TrafficControlLayer> ();
nodesB.Get (0)->AggregateObject (tcB);
queue->SetNetDevice (txDevB);
tcB->SetRootQueueDiscOnDevice (txDevB, queue);
tcB->Initialize ();
burst = 15000;
mtu = 1000;
rate = DataRate ("15KB/s");
peakRate = DataRate ("20KB/s");
if (mode == QueueSizeUnit::BYTES)
{
modeSize = pktSize;
qSize = qSize * modeSize;
}
NS_TEST_EXPECT_MSG_EQ (queue->SetAttributeFailSafe ("MaxSize", QueueSizeValue (QueueSize (mode, qSize))),
true, "Verify that we can actually set the attribute MaxSize");
NS_TEST_EXPECT_MSG_EQ (queue->SetAttributeFailSafe ("Burst", UintegerValue (burst)), true,
"Verify that we can actually set the attribute Burst");
NS_TEST_EXPECT_MSG_EQ (queue->SetAttributeFailSafe ("Mtu", UintegerValue (mtu)), true,
"Verify that we can actually set the attribute Mtu");
NS_TEST_EXPECT_MSG_EQ (queue->SetAttributeFailSafe ("Rate", DataRateValue (rate)), true,
"Verify that we can actually set the attribute Rate");
NS_TEST_EXPECT_MSG_EQ (queue->SetAttributeFailSafe ("PeakRate", DataRateValue (peakRate)), true,
"Verify that we can actually set the attribute PeakRate");
queue->Initialize ();
delay = 0.04;
for (uint32_t i = 1; i <= nPkt; i++)
{
Simulator::Schedule (Time (Seconds ((i + 1) * delay)), &TbfQueueDiscTestCase::Enqueue, this, queue, dest, pktSize);
}
for (uint32_t i = 1; i <= nPkt; i++)
{
if (i % 2 == 1)
{
Simulator::Schedule (Time (Seconds ((i + 1) * delay + 0.02)), &TbfQueueDiscTestCase::DequeueAndCheck, this,
queue, true, "1st packet should not be blocked");
}
else
{
Simulator::Schedule (Time (Seconds ((i + 1) * delay + 0.02)), &TbfQueueDiscTestCase::DequeueAndCheck, this,
queue, false, "This packet should be blocked");
}
}
Simulator::Stop (Seconds (0.55));
Simulator::Run ();
}
void
TbfQueueDiscTestCase::Enqueue (Ptr<TbfQueueDisc> queue, Address dest, uint32_t size)
{
queue->Enqueue (Create<TbfQueueDiscTestItem> (Create<Packet> (size), dest));
}
void
TbfQueueDiscTestCase::DequeueAndCheck (Ptr<TbfQueueDisc> queue, bool flag, std::string printStatement)
{
Ptr<QueueDiscItem> item = queue->Dequeue ();
NS_TEST_EXPECT_MSG_EQ ((item != 0), flag, printStatement);
}
void
TbfQueueDiscTestCase::DoRun (void)
{
RunTbfTest (QueueSizeUnit::PACKETS);
RunTbfTest (QueueSizeUnit::BYTES);
Simulator::Destroy ();
}
/**
* \ingroup traffic-control-test
* \ingroup tests
*
* \brief Tbf Queue Disc Test Suite
*/
static class TbfQueueDiscTestSuite : public TestSuite
{
public:
TbfQueueDiscTestSuite ()
: TestSuite ("tbf-queue-disc", UNIT)
{
AddTestCase (new TbfQueueDiscTestCase (), TestCase::QUICK);
}
} g_tbfQueueTestSuite; ///< the test suite

View File

@@ -19,6 +19,7 @@ def build(bld):
'model/fq-codel-queue-disc.cc',
'model/pie-queue-disc.cc',
'model/mq-queue-disc.cc',
'model/tbf-queue-disc.cc',
'helper/traffic-control-helper.cc',
'helper/queue-disc-container.cc'
]
@@ -30,6 +31,7 @@ def build(bld):
'test/adaptive-red-queue-disc-test-suite.cc',
'test/pie-queue-disc-test-suite.cc',
'test/fifo-queue-disc-test-suite.cc',
'test/tbf-queue-disc-test-suite.cc',
'test/tc-flow-control-test-suite.cc'
]
@@ -46,6 +48,7 @@ def build(bld):
'model/fq-codel-queue-disc.h',
'model/pie-queue-disc.h',
'model/mq-queue-disc.h',
'model/tbf-queue-disc.h',
'helper/traffic-control-helper.h',
'helper/queue-disc-container.h'
]