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

 

 

Back to NS3 Learning Guide

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