diff --git a/src/internet/model/tcp-socket-base.cc b/src/internet/model/tcp-socket-base.cc index 760101a61..4482a80e0 100644 --- a/src/internet/model/tcp-socket-base.cc +++ b/src/internet/model/tcp-socket-base.cc @@ -58,6 +58,7 @@ #include "tcp-option-sack.h" #include "tcp-congestion-ops.h" #include "tcp-recovery-ops.h" +#include "ns3/tcp-rate-ops.h" #include #include @@ -243,6 +244,7 @@ TcpSocketBase::TcpSocketBase (void) m_rxBuffer = CreateObject (); m_txBuffer = CreateObject (); m_tcb = CreateObject (); + m_rateOps = CreateObject (); m_tcb->m_currentPacingRate = m_tcb->m_maxPacingRate; m_pacingTimer.SetFunction (&TcpSocketBase::NotifyPacingPerformed, this); @@ -370,6 +372,8 @@ TcpSocketBase::TcpSocketBase (const TcpSocketBase& sock) m_recoveryOps = sock.m_recoveryOps->Fork (); } + m_rateOps = CreateObject (); + bool ok; ok = m_tcb->TraceConnectWithoutContext ("CongestionWindow", @@ -801,6 +805,11 @@ TcpSocketBase::Send (Ptr p, uint32_t flags) m_errno = ERROR_SHUTDOWN; return -1; } + + m_rateOps->CalculateAppLimited(m_tcb->m_cWnd, m_tcb->m_bytesInFlight, m_tcb->m_segmentSize, + m_txBuffer->TailSequence (), m_tcb->m_nextTxSequence, + m_txBuffer->GetLost (), m_txBuffer->GetRetransmitsCount ()); + // Submit the data to lower layers NS_LOG_LOGIC ("txBufSize=" << m_txBuffer->Size () << " state " << TcpStateName[m_state]); if ((m_state == ESTABLISHED || m_state == CLOSE_WAIT) && AvailableWindow () > 0) @@ -1529,7 +1538,7 @@ TcpSocketBase::ReadOptions (const TcpHeader &tcpHeader, uint32_t *bytesSacked) } void -TcpSocketBase::EnterRecovery () +TcpSocketBase::EnterRecovery (uint32_t currentDelivered) { NS_LOG_FUNCTION (this); NS_ASSERT (m_tcb->m_congState != TcpSocketState::CA_RECOVERY); @@ -1582,7 +1591,7 @@ TcpSocketBase::EnterRecovery () } void -TcpSocketBase::DupAck () +TcpSocketBase::DupAck (uint32_t currentDelivered) { NS_LOG_FUNCTION (this); // NOTE: We do not count the DupAcks received in CA_LOSS, because we @@ -1636,7 +1645,7 @@ TcpSocketBase::DupAck () // (1) If DupAcks >= DupThresh, go to step (4). if ((m_dupAckCount == m_retxThresh) && (m_highRxAckMark >= m_recover)) { - EnterRecovery (); + EnterRecovery (currentDelivered); NS_ASSERT (m_tcb->m_congState == TcpSocketState::CA_RECOVERY); } // (2) If DupAcks < DupThresh but IsLost (HighACK + 1) returns true @@ -1645,7 +1654,7 @@ TcpSocketBase::DupAck () // go to step (4). else if (m_txBuffer->IsLost (m_highRxAckMark + m_tcb->m_segmentSize)) { - EnterRecovery (); + EnterRecovery (currentDelivered); NS_ASSERT (m_tcb->m_congState == TcpSocketState::CA_RECOVERY); } else @@ -1681,11 +1690,14 @@ TcpSocketBase::ReceivedAck (Ptr packet, const TcpHeader& tcpHeader) // Upon the receipt of any ACK containing SACK information, the // scoreboard MUST be updated via the Update () routine (done in ReadOptions) uint32_t bytesSacked = 0; + uint64_t previousDelivered = m_rateOps->GetConnectionRate ().m_delivered; ReadOptions (tcpHeader, &bytesSacked); SequenceNumber32 ackNumber = tcpHeader.GetAckNumber (); SequenceNumber32 oldHeadSequence = m_txBuffer->HeadSequence (); - m_txBuffer->DiscardUpTo (ackNumber); + m_txBuffer->DiscardUpTo (ackNumber, MakeCallback (&TcpRateOps::SkbDelivered, m_rateOps)); + + uint32_t currentDelivered = static_cast (m_rateOps->GetConnectionRate ().m_delivered - previousDelivered); if (ackNumber > oldHeadSequence && (m_tcb->m_ecnState != TcpSocketState::ECN_DISABLED) && (tcpHeader.GetFlags () & TcpHeader::ECE)) { @@ -1704,7 +1716,7 @@ TcpSocketBase::ReceivedAck (Ptr packet, const TcpHeader& tcpHeader) // RFC 6675 Section 5: 2nd, 3rd paragraph and point (A), (B) implementation // are inside the function ProcessAck - ProcessAck (ackNumber, (bytesSacked > 0), oldHeadSequence); + ProcessAck (ackNumber, (bytesSacked > 0), currentDelivered, oldHeadSequence); // If there is any data piggybacked, store it into m_rxBuffer if (packet->GetSize () > 0) @@ -1718,8 +1730,8 @@ TcpSocketBase::ReceivedAck (Ptr packet, const TcpHeader& tcpHeader) } void -TcpSocketBase::ProcessAck (const SequenceNumber32 &ackNumber, bool scoreboardUpdated, - const SequenceNumber32 &oldHeadSequence) +TcpSocketBase::ProcessAck(const SequenceNumber32 &ackNumber, bool scoreboardUpdated, + uint32_t currentDelivered, const SequenceNumber32 &oldHeadSequence) { NS_LOG_FUNCTION (this << ackNumber << scoreboardUpdated); // RFC 6675, Section 5, 2nd paragraph: @@ -1728,6 +1740,7 @@ TcpSocketBase::ProcessAck (const SequenceNumber32 &ackNumber, bool scoreboardUpd bool exitedFastRecovery = false; uint32_t oldDupAckCount = m_dupAckCount; // remember the old value m_tcb->m_lastAckedSeq = ackNumber; // Update lastAckedSeq + uint32_t bytesAcked = 0; /* In RFC 5681 the definition of duplicate acknowledgment was strict: * @@ -1765,7 +1778,7 @@ TcpSocketBase::ProcessAck (const SequenceNumber32 &ackNumber, bool scoreboardUpd { // loss recovery check is done inside this function thanks to // the congestion state machine - DupAck (); + DupAck (currentDelivered); } if (ackNumber == oldHeadSequence @@ -1791,13 +1804,15 @@ TcpSocketBase::ProcessAck (const SequenceNumber32 &ackNumber, bool scoreboardUpd { // Please remember that, with SACK, we can enter here even if we // received a dupack. - uint32_t bytesAcked = ackNumber - oldHeadSequence; + bytesAcked = ackNumber - oldHeadSequence; uint32_t segsAcked = bytesAcked / m_tcb->m_segmentSize; m_bytesAckedNotProcessed += bytesAcked % m_tcb->m_segmentSize; + bytesAcked -= bytesAcked % m_tcb->m_segmentSize; if (m_bytesAckedNotProcessed >= m_tcb->m_segmentSize) { segsAcked += 1; + bytesAcked += m_tcb->m_segmentSize; m_bytesAckedNotProcessed -= m_tcb->m_segmentSize; } @@ -2841,13 +2856,13 @@ TcpSocketBase::SendDataPacket (SequenceNumber32 seq, uint32_t maxSize, bool with { NS_LOG_FUNCTION (this << seq << maxSize << withAck); - bool isRetransmission = false; - if (seq != m_tcb->m_highTxMark) - { - isRetransmission = true; - } + bool isStartOfTransmission = BytesInFlight () == 0U; + TcpTxItem *outItem = m_txBuffer->CopyFromSequence (maxSize, seq); - Ptr p = m_txBuffer->CopyFromSequence (maxSize, seq)->GetPacketCopy (); + m_rateOps->SkbSent(outItem, isStartOfTransmission); + + bool isRetransmission = outItem->IsRetrans (); + Ptr p = outItem->GetPacketCopy (); uint32_t sz = p->GetSize (); // Size of packet uint8_t flags = withAck ? TcpHeader::ACK : 0; uint32_t remainingData = m_txBuffer->SizeFromSequence (seq + SequenceNumber32 (sz)); @@ -2964,7 +2979,7 @@ TcpSocketBase::SendDataPacket (SequenceNumber32 seq, uint32_t maxSize, bool with } // Notify the application of the data being sent unless this is a retransmit - if (seq + sz > m_tcb->m_highTxMark) + if (!isRetransmission) { Simulator::ScheduleNow (&TcpSocketBase::NotifyDataSent, this, (seq + sz - m_tcb->m_highTxMark.Get ())); @@ -3952,7 +3967,7 @@ TcpSocketBase::ProcessOptionSack (const Ptr option) NS_LOG_FUNCTION (this << option); Ptr s = DynamicCast (option); - return m_txBuffer->Update (s->GetSackList ()); + return m_txBuffer->Update (s->GetSackList (), MakeCallback (&TcpRateOps::SkbDelivered, m_rateOps)); } void diff --git a/src/internet/model/tcp-socket-base.h b/src/internet/model/tcp-socket-base.h index 2ac94698c..193b26a5c 100644 --- a/src/internet/model/tcp-socket-base.h +++ b/src/internet/model/tcp-socket-base.h @@ -49,6 +49,7 @@ class TcpTxBuffer; class TcpOption; class Ipv4Interface; class Ipv6Interface; +class TcpRateOps; /** * \ingroup tcp @@ -965,9 +966,11 @@ protected: * \param scoreboardUpdated if true indicates that the scoreboard has been * \param oldHeadSequence value of HeadSequence before ack * updated with SACK information + * \param currentDelivered The number of bytes (S)ACKed + * \return the number of bytes (newly) acked, or 0 if it was a dupack */ virtual void ProcessAck (const SequenceNumber32 &ackNumber, bool scoreboardUpdated, - const SequenceNumber32 &oldHeadSequence); + uint32_t currentDelivered, const SequenceNumber32 &oldHeadSequence); /** * \brief Recv of a data, put into buffer, call L7 to get it if necessary @@ -1002,13 +1005,17 @@ protected: /** * \brief Dupack management + * + * \param currentDelivered Current (S)ACKed bytes */ - void DupAck (); + void DupAck (uint32_t currentDelivered); /** * \brief Enter the CA_RECOVERY, and retransmit the head + * + * \param currentDelivered Currently (S)ACKed bytes */ - void EnterRecovery (); + void EnterRecovery (uint32_t currentDelivered); /** * \brief An RTO event happened @@ -1252,6 +1259,7 @@ protected: Ptr m_tcb; //!< Congestion control information Ptr m_congestionControl; //!< Congestion control Ptr m_recoveryOps; //!< Recovery Algorithm + Ptr m_rateOps; //!< Rate operations // Guesses over the other connection end bool m_isFirstPartialAck {true}; //!< First partial ACK during RECOVERY