How to add a weighted round robin queue into NS3?
In this
lab, I will show how to create two queues, i.e. Q0 and Q1. The packets that the
TOS is set to 16 will go to Q0. The packets that the TOS is set to 0 (default)
will go to Q1. You can set the weights to Q0 and Q1. For example, 3 for Q0 and
2 for Q1. Then when the weighted round robin queue dequeues the packets, it
will choose three packets from Q0, two packets from Q1, three packet from Q0,
two packets from Q1, and so on.
mwyrr-queue-disc.h (put this file under src/traffic-control/model)
/*
-*- Mode:C++; c-file-style:"gnu";
indent-tabs-mode:nil; -*- */ /* * Copyright (c) 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: Chih-Heng Ke <smallko@gmail.com> */ #ifndef
myWRR_QUEUE_DISC_H #define
myWRR_QUEUE_DISC_H #include
"ns3/queue-disc.h" namespace
ns3 { /** * \ingroup traffic-control * * Simple queue disc implementing the
FIFO (First-In First-Out) policy. * */ class
myWRRQueueDisc : public QueueDisc
{ public: /** * \brief Get the type ID. * \return the object TypeId */ static TypeId
GetTypeId (void); /** * \brief myWRRQueueDisc
constructor * * Creates a queue with a depth
of 1000 packets by default */ myWRRQueueDisc
(); virtual ~myWRRQueueDisc(); // Reasons for dropping packets static constexpr
const char* LIMIT_EXCEEDED_DROP = "Queue disc limit exceeded"; //!< Packet dropped due to queue
disc limit exceeded 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); uint32_t m_turn; //turn=0: serving queue0, turn=1:
serving queue1 uint32_t m_weight0; // weight for
queue0 uint32_t m_weight1; // weight for
queue1 uint32_t curr_weight0; // current weight for queue0 uint32_t curr_weight1; // current weight for queue1 }; } //
namespace ns3 #endif
/* myWRR_QUEUE_DISC_H */ |
mwyrr-queue-disc.cc (put this file under src/traffic-control/model)
/*
-*- Mode:C++; c-file-style:"gnu";
indent-tabs-mode:nil; -*- */ /* * Copyright (c) 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: Chih-Heng Ke <smallko@gmail.com> */ #include
"ns3/log.h" #include
"mywrr-queue-disc.h" #include
"ns3/object-factory.h" #include
"ns3/drop-tail-queue.h" #include
"ns3/socket.h" namespace
ns3 { NS_LOG_COMPONENT_DEFINE
("myWRRQueueDisc"); NS_OBJECT_ENSURE_REGISTERED
(myWRRQueueDisc); TypeId myWRRQueueDisc::GetTypeId
(void) { static TypeId
tid = TypeId ("ns3::myWRRQueueDisc") .SetParent<QueueDisc> () .SetGroupName
("TrafficControl") .AddConstructor<myWRRQueueDisc> () .AddAttribute
("MaxSize",
"The max queue size",
QueueSizeValue (QueueSize
("1000p")),
MakeQueueSizeAccessor (&QueueDisc::SetMaxSize,
&QueueDisc::GetMaxSize),
MakeQueueSizeChecker ()) .AddAttribute
("Weight0",
"weight for queue0",
UintegerValue (1),
MakeUintegerAccessor (&myWRRQueueDisc::m_weight0),
MakeUintegerChecker<uint32_t> ()) .AddAttribute
("Weight1",
"weight for queue1",
UintegerValue (1),
MakeUintegerAccessor (&myWRRQueueDisc::m_weight1),
MakeUintegerChecker<uint32_t> ()) ; return tid; } myWRRQueueDisc::myWRRQueueDisc () : QueueDisc
(QueueDiscSizePolicy::MULTIPLE_QUEUES, QueueSizeUnit::PACKETS) { NS_LOG_FUNCTION (this); } myWRRQueueDisc::~myWRRQueueDisc () { NS_LOG_FUNCTION (this); } bool myWRRQueueDisc::DoEnqueue (Ptr<QueueDiscItem> item) { NS_LOG_FUNCTION (this << item); if (GetCurrentSize
() + item > GetMaxSize ()) { NS_LOG_LOGIC
("Queue full -- dropping pkt"); DropBeforeEnqueue (item, LIMIT_EXCEEDED_DROP); return false; } uint8_t priority = 0; SocketPriorityTag
priorityTag; uint32_t band; if (item->GetPacket
()->PeekPacketTag (priorityTag)) { priority = priorityTag.GetPriority (); //std::cout << "priority: " << priority
<< std::endl; band =
(uint32_t) priority & 0x0f; //std::cout << "band: " << band <<
std::endl; } bool retval; if (band==6) { retval
= GetInternalQueue (0)->Enqueue (item); if (!retval) {
//NS_LOG_WARN ("Packet enqueue failed. Check the size of the
internal queues"); } else {
//NS_LOG_LOGIC ("Enqueue: Queue0"); } } else { retval
= GetInternalQueue (1)->Enqueue (item); if (!retval) {
//NS_LOG_WARN ("Packet enqueue failed. Check the size of the
internal queues"); } else {
//NS_LOG_LOGIC ("Enqueue: Queue1"); } } return retval; } Ptr<QueueDiscItem> myWRRQueueDisc::DoDequeue (void) { NS_LOG_FUNCTION (this); Ptr<QueueDiscItem> item; if (m_turn==0)
{ item = GetInternalQueue
(0)->Dequeue (); if (item!=0) { curr_weight0++; if
(curr_weight0==m_weight0){
curr_weight0=0; m_turn=1; } NS_LOG_LOGIC
("Dequeue from Queue0"); return item; } else {
curr_weight0=0; m_turn=1;
item = GetInternalQueue (1)->Dequeue (); if
(item!=0) {
curr_weight1++;
if (curr_weight1==m_weight1){
curr_weight1=0;
m_turn=0;
}
NS_LOG_LOGIC ("Dequeue from Queue1");
return item; } } } else { item = GetInternalQueue (1)->Dequeue (); if (item!=0) {
curr_weight1++; if
(curr_weight1==m_weight1){
curr_weight1=0;
m_turn=0; }
NS_LOG_LOGIC ("Dequeue from Queue1"); return item; } else {
curr_weight1=0; m_turn=0;
item = GetInternalQueue (0)->Dequeue (); if
(item!=0) {
curr_weight0++;
if (curr_weight0==m_weight0){
curr_weight0=0;
m_turn=1;
}
NS_LOG_LOGIC ("Dequeue from Queue0");
return item; } } } NS_LOG_LOGIC ("Queue
empty"); return item; } Ptr<const QueueDiscItem> myWRRQueueDisc::DoPeek (void) { NS_LOG_FUNCTION (this); Ptr<const
QueueDiscItem> item; for (uint32_t i
= 0; i < GetNInternalQueues
(); i++) { if ((item = GetInternalQueue (i)->Peek
()) != 0) {
NS_LOG_LOGIC ("Peeked from band " << i << ": " << item); NS_LOG_LOGIC
("Number packets band " << i
<< ": " << GetInternalQueue (i)->GetNPackets ());
return item; } } NS_LOG_LOGIC ("Queue
empty"); return item; } bool myWRRQueueDisc::CheckConfig (void) { NS_LOG_FUNCTION (this); if (GetNQueueDiscClasses
() > 0) { NS_LOG_ERROR
("myWRRQueueDisc cannot have classes"); return false; } if (GetNPacketFilters
() > 0) { NS_LOG_ERROR
("myWRRQueueDisc needs no packet
filter"); return false; } if (GetNInternalQueues
() == 0) { // create 2 DropTail queues with GetLimit()
packets each ObjectFactory factory; factory.SetTypeId ("ns3::DropTailQueue<QueueDiscItem>"); factory.Set ("MaxSize",
QueueSizeValue (GetMaxSize
())); AddInternalQueue (factory.Create<InternalQueue> ()); AddInternalQueue (factory.Create<InternalQueue> ());
} if (GetNInternalQueues
() != 2) { NS_LOG_ERROR
("myWRRQueueDisc needs 2 internal
queue"); return false; } if (GetInternalQueue
(0)-> GetMaxSize ().GetUnit
() != QueueSizeUnit::PACKETS || GetInternalQueue (1)-> GetMaxSize
().GetUnit () != QueueSizeUnit::PACKETS
) { NS_LOG_ERROR
("myWRRQueueDisc needs 2 internal queues
operating in packet mode"); return false; } for (uint8_t i
= 0; i < 2; i++) { if (GetInternalQueue (i)->GetMaxSize () < GetMaxSize
()) {
NS_LOG_ERROR ("The capacity of some internal queue(s) is less
than the queue disc capacity");
return false; } } return true; } void myWRRQueueDisc::InitializeParams (void) { NS_LOG_FUNCTION (this); curr_weight0=0; curr_weight1=0; } } //
namespace ns3 |
modify the wscript under src/traffic-control
test-mywrr.cc (put this file under scratch)
#include <fstream> #include <string.h>
#include "ns3/core-module.h" #include "ns3/internet-module.h" #include "ns3/point-to-point-module.h" #include "ns3/packet-sink.h" #include "ns3/packet-sink-helper.h" #include "ns3/on-off-helper.h" #include "ns3/traffic-control-module.h"
using namespace ns3;
NS_LOG_COMPONENT_DEFINE ("test-mywrr");
QueueDiscContainer queueDiscs; const int no=2; /* number of tcp flows */ Ptr<PacketSink> sink[no]; /* Pointer to the packet sink application */ uint64_t lastTotalRx[no]; /* The value of the last total received bytes */ double cur[no]; void CalculateThroughput () { Time now = Simulator::Now (); std::cout << now.GetSeconds (); for(int j=0;j<no;j++){ cur[j] = (sink[j]->GetTotalRx () - lastTotalRx[j]) * (double) 8 / 1e3; std::cout << "\t" << cur[j]; lastTotalRx[j] = sink[j]->GetTotalRx (); } std::cout << std::endl; Simulator::Schedule (MilliSeconds (1000), &CalculateThroughput); } int main (int argc, char *argv[]) { LogComponentEnable ("myWRRQueueDisc", LOG_LEVEL_LOGIC);
NS_LOG_INFO ("Create nodes."); NodeContainer n; n.Create (2);
TrafficControlHelper tch; tch.SetRootQueueDisc
("ns3::myWRRQueueDisc"); Config::SetDefault
("ns3::myWRRQueueDisc::MaxSize",
QueueSizeValue (QueueSize
(QueueSizeUnit::PACKETS, 100))); Config::SetDefault
("ns3::myWRRQueueDisc::Weight0", UintegerValue(3)); Config::SetDefault
("ns3::myWRRQueueDisc::Weight1", UintegerValue(2));
InternetStackHelper internet; internet.Install (n);
NS_LOG_INFO ("Create channels.");
PointToPointHelper pointToPoint; pointToPoint.SetDeviceAttribute ("DataRate", StringValue ("100kbps")); pointToPoint.SetChannelAttribute ("Delay", StringValue ("1ms")); pointToPoint.SetDeviceAttribute("Mtu", UintegerValue(1400)); NetDeviceContainer p2pDevices; p2pDevices = pointToPoint.Install (n);
queueDiscs = tch.Install
(p2pDevices.Get(0));
Ipv4AddressHelper ipv4;
NS_LOG_INFO ("Assign IP Addresses."); ipv4.SetBase ("10.1.1.0", "255.255.255.0"); Ipv4InterfaceContainer i = ipv4.Assign (p2pDevices);
NS_LOG_INFO ("Create Applications.");
PacketSinkHelper sinkHelper ("ns3::UdpSocketFactory", InetSocketAddress (Ipv4Address::GetAny (), 9)); ApplicationContainer sinkApp = sinkHelper.Install (n.Get(1)); sink[0] = StaticCast<PacketSink> (sinkApp.Get (0));
InetSocketAddress sinkSocket (i.GetAddress (1), 9);
sinkSocket.SetTos (16); OnOffHelper server ("ns3::UdpSocketFactory", sinkSocket); server.SetAttribute ("PacketSize", UintegerValue (1000)); server.SetAttribute ("OnTime", StringValue ("ns3::ConstantRandomVariable[Constant=1]")); server.SetAttribute ("OffTime", StringValue ("ns3::ConstantRandomVariable[Constant=0]")); server.SetAttribute ("DataRate", DataRateValue (DataRate ("100Kbps"))); ApplicationContainer serverApp = server.Install (n.Get(0)); sinkApp.Start (Seconds (0.0)); serverApp.Start (Seconds (1.0));
PacketSinkHelper sinkHelper2 ("ns3::UdpSocketFactory", InetSocketAddress (Ipv4Address::GetAny (), 10)); ApplicationContainer sinkApp2 = sinkHelper2.Install (n.Get(1)); sink[1] = StaticCast<PacketSink> (sinkApp2.Get (0));
InetSocketAddress sinkSocket2 (i.GetAddress (1), 10);
sinkSocket2.SetTos (0); OnOffHelper server2 ("ns3::UdpSocketFactory", sinkSocket2); server2.SetAttribute ("PacketSize", UintegerValue (1000)); server2.SetAttribute ("OnTime", StringValue ("ns3::ConstantRandomVariable[Constant=1]")); server2.SetAttribute ("OffTime", StringValue ("ns3::ConstantRandomVariable[Constant=0]")); server2.SetAttribute ("DataRate", DataRateValue (DataRate ("100kbps"))); ApplicationContainer serverApp2 = server2.Install (n.Get(0)); sinkApp2.Start (Seconds (0.0)); serverApp2.Start (Seconds (1.0));
//Simulator::Schedule (Seconds (1.0), &CalculateThroughput);
Simulator::Stop (Seconds (12.0)); pointToPoint.EnablePcapAll("tos-udp"); NS_LOG_INFO ("Run Simulation."); Simulator::Run (); Simulator::Destroy (); NS_LOG_INFO ("Done.");
} |
Execution
Last Modified: 2022/2/21 done
[Author]
Dr. Chih-Heng Ke
Department
of Computer Science and Information Engineering, National Quemoy
University, Kinmen, Taiwan
Email:
smallko@gmail.com