Skip to content

Fix instant send in SimpleNetDevice when queue is empty or full

This is a follow-up to MR !409 (closed)

Looking at logs from the same test as before (tc-flow-control-test-suite) I realized that the second netdevice was receiving the first packet at time=0, even though the transmitting SimpleNetDevice had a speed of 1Mbps.

In this log, note that the timestamps are all zero, with SimpleNetDevice::SendFrom being called first and then SimpleChannel::Send and SimpleNetDevice::Receive (on the other end of the link) both being called at exactly the same time (0.000 seconds):

$ NS_LOG="SimpleNetDevice:SimpleChannel" build/utils/ns3-dev-test-runner-debug --suite=tc-flow-control 2>&1 | grep -E ':Transmit|:Receive|:SendFrom|:Send'
+0.000000000s -1 SimpleNetDevice:Send(0x7f9e916989d0, 0x7f9e916083d0, 04-06-00:00:00:00:00:00, 0)
+0.000000000s -1 SimpleNetDevice:SendFrom(0x7f9e916989d0, 0x7f9e916083d0, 04-06-00:00:00:00:00:02, 04-06-00:00:00:00:00:00, 0)
+0.000000000s -1 SimpleChannel:Send(0x7f9ea176a4d0, 0x7f9e916083d0, 0, 00:00:00:00:00:00, 00:00:00:00:00:02, 0x7f9e916989d0)
+0.000000000s -1 SimpleNetDevice:Send(0x7f9e916989d0, 0x7f9ea176a200, 04-06-00:00:00:00:00:00, 0)
+0.000000000s -1 SimpleNetDevice:SendFrom(0x7f9e916989d0, 0x7f9ea176a200, 04-06-00:00:00:00:00:02, 04-06-00:00:00:00:00:00, 0)
+0.000000000s 1 SimpleNetDevice:Receive(0x7f9ea176a5d0, 0x7f9ea172e3f0, 0, 00:00:00:00:00:00, 00:00:00:00:00:02)

This isn't caught by the TC test because the test only checks stats about the sending NetDevice, not the receiving one.

This MR changes the flow a bit to make this more realistic:

  1. Instead of calling m_channel->Send() inside of SendFrom(), we call ScheduleTransmit(), which dequeues a packet from the head of the queue, puts it into the member pointer m_transmittingPacket, and schedules TransmitComplete for the correct time in the future
  2. When TransmitComplete is called (at the end of the transmitting time), it now assumes m_transmittingPacket is not null (there's an assert for this) and then calls m_channel->Send().
  3. TransmitComplete calls ScheduleTransmit which checks if there are any packets in the queue and, if so, schedules another transmission event.

I also removed what I think is a bug from the end of SendFrom: previously, if the m_queue->Enqueue(p) call failed, m_channel->Send() would be called immediately. This doesn't make any sense for two reasons:

  1. If the device queue is full, how can it be sent? Is this meant to handle a 0-length queue?
  2. It shouldn't call Send() immediately no matter what, it should schedule a transmission in the future.

I went with the behavior of returning false and not scheduling a transmission, which is what it seems like other NetDevices do and feels correct to me.

Here's the equivalent log as above, with the fix. Note that SimpleNetDevice::SendFrom is still called at 0.000s, but SimpleChannel::Send and SimpleNetDevice::Receive are both called at 0.008s.

$ NS_LOG="SimpleNetDevice:SimpleChannel" build/utils/ns3-dev-test-runner-debug --suite=tc-flow-control 2>&1 | grep -E ':Transmit|:Receive|:SendFrom|:Send' | head -n 10
+0.000000000s -1 SimpleNetDevice:Send(0x7f949cd5caa0, 0x7f94bcc1c7c0, 04-06-00:00:00:00:00:00, 0)
+0.000000000s -1 SimpleNetDevice:SendFrom(0x7f949cd5caa0, 0x7f94bcc1c7c0, 04-06-00:00:00:00:00:02, 04-06-00:00:00:00:00:00, 0)
+0.000000000s -1 SimpleNetDevice:Send(0x7f949cd5caa0, 0x7f94bcc1c0f0, 04-06-00:00:00:00:00:00, 0)
+0.000000000s -1 SimpleNetDevice:SendFrom(0x7f949cd5caa0, 0x7f94bcc1c0f0, 04-06-00:00:00:00:00:02, 04-06-00:00:00:00:00:00, 0)
+0.008000000s -1 SimpleNetDevice:TransmitComplete(0x7f949cd5caa0)
+0.008000000s -1 SimpleChannel:Send(0x7f949cd5c3b0, 0x7f94bcc1c7c0, 0, 00:00:00:00:00:00, 00:00:00:00:00:02, 0x7f949cd5caa0)
+0.008000000s 1 SimpleNetDevice:Receive(0x7f949cd5c440, 0x7f94bcc1a500, 0, 00:00:00:00:00:00, 00:00:00:00:00:02)
Edited by Greg Steinbrecher

Merge request reports