internet: Extra retransmissions on receiving partial ACK
To test and align the ns-3 implementation of PRR with Linux, I created a scenario where I am sending 20 packets from the sender to the receiver and dropping 3rd, 5th, 6th 7th and 8th packet with SACK enabled and initial cwnd of 10 segments. The following diagram explains the scenario.

In the above scenario, on receiving the partial ACK for the 5th packet, 5th packet is retransmitted again which is happening due to the following code:
// (B) Upon receipt of an ACK that does not cover RecoveryPoint, the
// following actions MUST be taken:
//
// (B.1) Use Update () to record the new SACK information conveyed
// by the incoming ACK.
// (B.2) Use SetPipe () to re-calculate the number of octets still
// in the network.
//
// (B.1) is done at the beginning, while (B.2) is delayed to part (C) while
// trying to transmit with SendPendingData. We are not allowed to exit
// the CA_RECOVERY phase. Just process this partial ack (RFC 5681)
if (ackNumber < m_recover && m_tcb->m_congState == TcpSocketState::CA_RECOVERY)
{
if (!m_sackEnabled)
{
// Manually set the head as lost, it will be retransmitted.
NS_LOG_INFO ("Partial ACK. Manually setting head as lost");
m_txBuffer->MarkHeadAsLost ();
}
else
{
// We received a partial ACK, if we retransmitted this segment
// probably is better to retransmit it
m_txBuffer->DeleteRetransmittedFlagFromHead ();
}
DoRetransmit (); // Assume the next seq is lost. Retransmit lost packet
m_tcb->m_cWndInfl = SafeSubtraction (m_tcb->m_cWndInfl, bytesAcked);
if (segsAcked >= 1)
{
m_recoveryOps->DoRecovery (m_tcb, bytesAcked, m_txBuffer->GetSacked ());
}
The retransmitted flag is removed from the Head and it is retransmitted again.
And in TcpSocketBase::SendPendingData () method one more packet (i.e., 18th packet) is send as pipe < cwnd because in PRR sendCount is calculated as 1 segment and cwnd is updated according to the following formula:
cwnd = pipe + sendCount;
While running the same scenario in DCE with Linux stack, on receiving the partial ACK for 5th packet, it was observed that 5th packet was not retransmitted again and only the 18th packet was sent from the sender to receiver due to sndcnt equals to 1.
Why in ns-3 a retransmitted packet is retransmitted again on receiving partial ACK? Due to this extra retransmission, the value of prr_out (total bytes sent during recovery) variable comes out to be different in ns-3 and Linux and hence making the cwnd values different.
Following are the steps to create the above scenario in ns-3:
-
Clone the following repository:
git clone https://gitlab.com/apoorvabhargava/ns-3-dev/tree/PRR-testing -
Run the following command in ns-3-dev:
./waf --run "dumbbell-topology-4-nodes --transport_prot=TcpLinuxReno --queue_disc_type=FifoQueueDisc --WindowScaling=true --Sack=true --delAckCount=1 --dataSize=524 --recovery=TcpLinuxPrrRecovery --BQL=true"
Also, if you want to create the same scenario in ns-3 DCE then, please refer to this file: Testing-Linux-PRR.zip which contains the example file, patch files, and a README file containing the steps to reproduce the result.