Tail Drop Queue not tail dropping (switch vs. node w/ internet stack)

139 views
Skip to first unread message

Luc

unread,
Jun 27, 2019, 1:09:27 PM6/27/19
to ns-3-users
Why does the tail drop queue not do a tail drop?

NS-3 version 3.29 (but I think it applies to all of them)

To reproduce:

We create a simple topology with 3 hosts and 1 host/switch in the middle.

(1) Create scratch/qtest/main.cc with the following code:

#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"

using namespace ns3;

int main() {

   
Time::SetResolution (Time::NS);

   
// Default port
    int default_port = 80;

   
// Hosts
    NodeContainer hosts;
    hosts
.Create(3);

   
// Switches
    NodeContainer switches;
    switches
.Create(1);

   
// All nodes
    NodeContainer nodes;
    nodes
.Add(hosts);
    nodes
.Add(switches);

   
// Install IP stack on all nodes
    InternetStackHelper stack;
    stack
.Install(nodes);

   
// Link model
    PointToPointHelper linkModel;
    linkModel
.SetQueue ("ns3::DropTailQueue<Packet>", "MaxSize", QueueSizeValue (QueueSize ("100p"))); // p in 100p stands for packets
    linkModel.SetDeviceAttribute ("DataRate", StringValue ("10Mbps"));
    linkModel
.SetChannelAttribute ("Delay", StringValue ("2ms"));

   
// Install links
    NetDeviceContainer linkHost0ToSwitch = linkModel.Install(nodes.Get(0), switches.Get(0));
   
NetDeviceContainer linkHost1ToSwitch = linkModel.Install(nodes.Get(1), switches.Get(0));
   
NetDeviceContainer linkHost2ToSwitch = linkModel.Install(nodes.Get(2), switches.Get(0));

   
// Assign IP addresses to all hosts
    Ipv4AddressHelper ipAssigner;
    ipAssigner
.SetBase ("10.0.0.0", "255.255.255.0");
   
Ipv4InterfaceContainer interfaces0toSwitch = ipAssigner.Assign (linkHost0ToSwitch);
    ipAssigner
.SetBase ("10.0.1.0", "255.255.255.0");
   
Ipv4InterfaceContainer interfaces1toSwitch = ipAssigner.Assign (linkHost1ToSwitch);
    ipAssigner
.SetBase ("10.0.2.0", "255.255.255.0");
   
Ipv4InterfaceContainer interfaces2toSwitch = ipAssigner.Assign (linkHost2ToSwitch);

   
// Calculate and populate IP routes
    Ipv4GlobalRoutingHelper::PopulateRoutingTables ();

   
// Create sink at node 2
    PacketSinkHelper sink("ns3::TcpSocketFactory", InetSocketAddress(Ipv4Address::GetAny(), default_port));
   
ApplicationContainer sinkApps;
    sinkApps
= sink.Install(hosts.Get(2));
    sinkApps
.Start(Seconds(0));
    sinkApps
.Stop(Seconds(1000.0));

   
// Create the two connections to the sink
    BulkSendHelper source("ns3::TcpSocketFactory", InetSocketAddress(interfaces2toSwitch.GetAddress(0), default_port));
    source
.SetAttribute("MaxBytes", UintegerValue(1000000));
    source
.Install(hosts.Get(0)).Start(Seconds(0));
    source
.Install(hosts.Get(1)).Start(Seconds(0));

   
// Run the simulator till completion
    Simulator::Run ();
   
Simulator::Destroy ();

   
return 0;

}

(2) Within src/network/utils/drop-tail-queue.cc set these functions for logging purposes:

#include "ns3/simulator.h"

// ...

template <typename Item>
bool
DropTailQueue<Item>::Enqueue (Ptr<Item> item)
{
  NS_LOG_FUNCTION
(this << item);
 
if ((GetCurrentSize()).GetValue() > 50) {
         
double current_time = Simulator::Now().ToDouble(Time::Unit::S);
        std
::cout << "Enqueueing at " << (GetCurrentSize()).GetValue() << " @ " << current_time << std::endl;
 
}

   
bool ret = DoEnqueue (Tail (), item);
   
if (!ret) {
      std
::cout << "DTQ: Dropping at size " << (GetCurrentSize()).GetValue() << std::endl;
   
}
   
return ret;

}

Now run it using 
./waf configure; ./waf --build-profile=optimized --disable-examples --disable-python; ./build/scratch/qtest/qtest > out.txt

A drop never happens (look at out.txt).
Similarly, you can see the cwnd growing unbounded by editing src/src/internet/model/tcp-socket-base.cc :

#include "ns3/simulator.h"

// ... with SendDataPacket add the following:

uint32_t
TcpSocketBase::SendDataPacket (SequenceNumber32 seq, uint32_t maxSize, bool withAck)
{
  NS_LOG_FUNCTION
(this << seq << maxSize << withAck);

 
double current_time = Simulator::Now().ToDouble(Time::Unit::S);
  std
::cout << "Sending data packet (cwnd = " << m_tcb->m_cWnd << ") @ " << current_time << std::endl;

// ... within TcpSocketBase::ProcessWait add the following:

  else if (tcpflags == TcpHeader::FIN || tcpflags == (TcpHeader::FIN | TcpHeader::ACK))
 
{ // Got FIN, respond with ACK and move to next state
    if (tcpflags & TcpHeader::ACK)
     
{ // Process the ACK first
        ReceivedAck (packet, tcpHeader);
     
}

     
double current_time = Simulator::Now().ToDouble(Time::Unit::S);
      std
::cout << "Speed: " << (1000000.0 * 8.0) / 1000000.0 / current_time << " Mbit/s" << std::endl;
      std
::cout << "Ending at t=." << current_time << std::endl;

// ...

Does anyone have an idea where the issue is caused? Possibly the 'switch' in the middle is buffering it in another buffer? If so, how do I disable this behavior as it is unlike-switch behavior?

In particular, how do I set a custom router/switch, in which I can put the forwarding rules (e.g, prefix-matching to next port/interface)?

Tom Henderson

unread,
Jun 27, 2019, 2:13:14 PM6/27/19
to ns-3-...@googlegroups.com
On 6/27/19 10:09 AM, Luc wrote:
> Why does the tail drop queue not do a tail drop?

You are hitting some limits in the priority queuing sublayer that exists
between the IP and device layer (this is the 'traffic-control' module in
ns-3). By default, a FqCoDel queue disc is installed on top of the
device. To see this in operation, try with logging enabled, such as:

NS_LOG="FqCoDelQueueDisc:QueueDisc" ./waf --run tail-drop > log.out 2>&1

In the log.out file, you should be able to see:

+0.280586726s 3 QueueDisc:DropAfterDequeue(0x913d50, 0x9d6250, "Target
exceeded drop")
+0.280586726s 3 QueueDisc:DropAfterDequeue(): [DEBUG] Total
packets/bytes dropped after dequeue: 1 / 588
+0.280586726s 3 QueueDisc:DropAfterDequeue(): [LOGIC]
m_traceDropAfterDequeue (p)
+0.280586726s 3 QueueDisc:DropAfterDequeue(0x90e590, 0x9d6250, "(Dropped
by child queue disc) Target exceeded drop")
+0.280586726s 3 QueueDisc:DropAfterDequeue(): [DEBUG] Total
packets/bytes dropped after dequeue: 1 / 588
+0.280586726s 3 QueueDisc:DropAfterDequeue(): [LOGIC]
m_traceDropAfterDequeue (p)

and other instances.
>
>
> In particular, how do I set a custom router/switch, in which I can put
> the forwarding rules (e.g, prefix-matching to next port/interface)?
>

We don't have a good L2 switch model (looking for contributions). We
have a lingering patch that many people worked or commented on, but that
didn't get merged because no one volunteered some test cases/criteria so
that we could write tests for it.

https://codereview.appspot.com/5615049/

If anyone is interested to rekindle that work (and in particular, write
down some test cases for such a device), let us know.

Meanwhile, you should be able to set static forwarding rules with IPv4
or IPv6 static routing on a router node; there are example programs in
the examples/ directory that do this.

- Tom
Reply all
Reply to author
Forward
0 new messages