How to add a round-robing 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. When the round robin queue dequeues the packets, it will choose a packet from Q0, Q1, Q0, Q1, and so on.
myrr-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 myRR_QUEUE_DISC_H #define myRR_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 myRRQueueDisc : public QueueDisc { public: /** * \brief Get the type ID. * \return the object TypeId */ static TypeId GetTypeId (void); /** * \brief myRRQueueDisc constructor * * Creates a queue with a depth of 1000 packets by default */ myRRQueueDisc (); virtual ~myRRQueueDisc(); // 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 }; } // namespace ns3 #endif /* myRR_QUEUE_DISC_H */ |
myrr-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 "myrr-queue-disc.h" #include "ns3/object-factory.h" #include "ns3/drop-tail-queue.h" #include "ns3/socket.h" namespace ns3 { NS_LOG_COMPONENT_DEFINE ("myRRQueueDisc"); NS_OBJECT_ENSURE_REGISTERED (myRRQueueDisc); TypeId myRRQueueDisc::GetTypeId (void) { static TypeId tid = TypeId ("ns3::myRRQueueDisc") .SetParent<QueueDisc> () .SetGroupName ("TrafficControl") .AddConstructor<myRRQueueDisc> () .AddAttribute ("MaxSize", "The max queue size", QueueSizeValue (QueueSize ("1000p")), MakeQueueSizeAccessor (&QueueDisc::SetMaxSize, &QueueDisc::GetMaxSize), MakeQueueSizeChecker ()) ; return tid; } myRRQueueDisc::myRRQueueDisc () : QueueDisc (QueueDiscSizePolicy::MULTIPLE_QUEUES, QueueSizeUnit::PACKETS) { NS_LOG_FUNCTION (this); } myRRQueueDisc::~myRRQueueDisc () { NS_LOG_FUNCTION (this); } bool myRRQueueDisc::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> myRRQueueDisc::DoDequeue (void) { NS_LOG_FUNCTION (this);
Ptr<QueueDiscItem> item;
if (m_turn==0) { item = GetInternalQueue (0)->Dequeue (); if (item!=0) { m_turn=1; NS_LOG_LOGIC ("Dequeue from Queue0"); return item; } else { item = GetInternalQueue (1)->Dequeue (); if (item!=0) { m_turn=0; NS_LOG_LOGIC ("Dequeue from Queue1"); return item; } } } else { item = GetInternalQueue (1)->Dequeue (); if (item!=0) { m_turn=0; NS_LOG_LOGIC ("Dequeue from Queue1"); return item; } else { item = GetInternalQueue (0)->Dequeue (); if (item!=0) { m_turn=1; NS_LOG_LOGIC ("Dequeue from Queue0"); return item; } } }
NS_LOG_LOGIC ("Queue empty"); return item; } Ptr<const QueueDiscItem> myRRQueueDisc::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 myRRQueueDisc::CheckConfig (void) { NS_LOG_FUNCTION (this); if (GetNQueueDiscClasses () > 0) { NS_LOG_ERROR ("myRRQueueDisc cannot have classes"); return false; } if (GetNPacketFilters () > 0) { NS_LOG_ERROR ("myRRQueueDisc 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 ("myRRQueueDisc needs 2 internal queue"); return false; }
if (GetInternalQueue (0)-> GetMaxSize ().GetUnit () != QueueSizeUnit::PACKETS || GetInternalQueue (1)-> GetMaxSize ().GetUnit () != QueueSizeUnit::PACKETS ) { NS_LOG_ERROR ("myRRQueueDisc 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 myRRQueueDisc::InitializeParams (void) { NS_LOG_FUNCTION (this); m_turn=0; } } // namespace ns3 |
modify the wscript under src/traffic-control
test-myrr.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 ("TOSUDP");
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 ("myRRQueueDisc", LOG_LEVEL_LOGIC);
NS_LOG_INFO ("Create nodes."); NodeContainer n; n.Create (2);
TrafficControlHelper tch; tch.SetRootQueueDisc
("ns3::myRRQueueDisc"); Config::SetDefault
("ns3::myRRQueueDisc::MaxSize", QueueSizeValue (QueueSize
(QueueSizeUnit::PACKETS, 100)));
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
We can see that packets are dequeued from Q0, Q1, Q0, Q1, and so on.
Last Modified: 2022/2/20 done
[Author]
Dr. Chih-Heng Ke
Department
of Computer Science and Information Engineering, National Quemoy
University, Kinmen, Taiwan
Email:
smallko@gmail.com