tcp: Added BBR Congestion control

This commit is contained in:
Vivek Jain
2020-04-09 22:50:37 +05:30
committed by Tom Henderson
parent b8ba1b70cb
commit 86755f4175
6 changed files with 1048 additions and 1 deletions

View File

@@ -0,0 +1,674 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2018 NITK Surathkal
*
* 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: Vivek Jain <jain.vivek.anand@gmail.com>
* Viyom Mittal <viyommittal@gmail.com>
* Mohit P. Tahiliani <tahiliani@nitk.edu.in>
*/
#include "tcp-bbr.h"
#include "ns3/log.h"
#include "ns3/tcp-socket-base.h"
namespace ns3 {
NS_LOG_COMPONENT_DEFINE ("TcpBbr");
NS_OBJECT_ENSURE_REGISTERED (TcpBbr);
const double TcpBbr::PACING_GAIN_CYCLE [] = {5.0 / 4, 3.0 / 4, 1, 1, 1, 1, 1, 1};
TypeId
TcpBbr::GetTypeId (void)
{
static TypeId tid = TypeId ("ns3::TcpBbr")
.SetParent<TcpCongestionOps> ()
.AddConstructor<TcpBbr> ()
.SetGroupName ("Internet")
.AddAttribute ("HighGain",
"Value of high gain",
DoubleValue (2.89),
MakeDoubleAccessor (&TcpBbr::m_highGain),
MakeDoubleChecker<double> ())
.AddAttribute ("BwWindowLength",
"Length of bandwidth windowed filter",
UintegerValue (10),
MakeUintegerAccessor (&TcpBbr::m_bandwidthWindowLength),
MakeUintegerChecker<uint32_t> ())
.AddAttribute ("RttWindowLength",
"Length of bandwidth windowed filter",
TimeValue (Seconds (10)),
MakeTimeAccessor (&TcpBbr::m_rtPropFilterLen),
MakeTimeChecker ())
.AddAttribute ("ProbeRttDuration",
"Length of bandwidth windowed filter",
TimeValue (MilliSeconds (200)),
MakeTimeAccessor (&TcpBbr::m_probeRttDuration),
MakeTimeChecker ())
;
return tid;
}
TcpBbr::TcpBbr ()
: TcpCongestionOps ()
{
NS_LOG_FUNCTION (this);
m_uv = CreateObject<UniformRandomVariable> ();
}
TcpBbr::TcpBbr (const TcpBbr &sock)
: TcpCongestionOps (sock),
m_bandwidthWindowLength (sock.m_bandwidthWindowLength),
m_pacingGain (sock.m_pacingGain),
m_cWndGain (sock.m_cWndGain),
m_highGain (sock.m_highGain),
m_isPipeFilled (sock.m_isPipeFilled),
m_minPipeCwnd (sock.m_minPipeCwnd),
m_roundCount (sock.m_roundCount),
m_roundStart (sock.m_roundStart),
m_nextRoundDelivered (sock.m_nextRoundDelivered),
m_probeRttDuration (sock.m_probeRttDuration),
m_probeRtPropStamp (sock.m_probeRtPropStamp),
m_probeRttDoneStamp (sock.m_probeRttDoneStamp),
m_probeRttRoundDone (sock.m_probeRttRoundDone),
m_packetConservation (sock.m_packetConservation),
m_priorCwnd (sock.m_priorCwnd),
m_idleRestart (sock.m_idleRestart),
m_targetCWnd (sock.m_targetCWnd),
m_fullBandwidth (sock.m_fullBandwidth),
m_fullBandwidthCount (sock.m_fullBandwidthCount),
m_rtProp (Time::Max ()),
m_sendQuantum (sock.m_sendQuantum),
m_cycleStamp (sock.m_cycleStamp),
m_cycleIndex (sock.m_cycleIndex),
m_rtPropExpired (sock.m_rtPropExpired),
m_rtPropFilterLen (sock.m_rtPropFilterLen),
m_rtPropStamp (sock.m_rtPropStamp),
m_isInitialized (sock.m_isInitialized),
m_delivered (sock.m_delivered),
m_appLimited (sock.m_appLimited), // TODO
m_txItemDelivered (sock.m_txItemDelivered) // TODO
{
NS_LOG_FUNCTION (this);
m_uv = CreateObject<UniformRandomVariable> ();
}
int64_t
TcpBbr::AssignStreams (int64_t stream)
{
NS_LOG_FUNCTION (this << stream);
m_uv->SetStream (stream);
return 1;
}
void
TcpBbr::InitRoundCounting ()
{
NS_LOG_FUNCTION (this);
m_nextRoundDelivered = 0;
m_roundStart = false;
m_roundCount = 0;
}
void
TcpBbr::InitFullPipe ()
{
NS_LOG_FUNCTION (this);
m_isPipeFilled = false;
m_fullBandwidth = 0;
m_fullBandwidthCount = 0;
}
void
TcpBbr::InitPacingRate (Ptr<TcpSocketState> tcb)
{
NS_LOG_FUNCTION (this << tcb);
if (!tcb->m_pacing)
{
NS_LOG_WARN ("BBR must use pacing");
tcb->m_pacing = true;
}
Time rtt = tcb->m_lastRtt != Time::Max () ? tcb->m_lastRtt.Get () : MilliSeconds (1);
DataRate nominalBandwidth (tcb->m_initialCWnd * tcb->m_segmentSize * 8 / rtt.GetSeconds ());
tcb->m_currentPacingRate = DataRate (m_pacingGain * nominalBandwidth.GetBitRate ());
}
void
TcpBbr::EnterStartup ()
{
NS_LOG_FUNCTION (this);
SetBbrState (BbrMode_t::BBR_STARTUP);
m_pacingGain = m_highGain;
m_cWndGain = m_highGain;
}
void
TcpBbr::HandleRestartFromIdle (Ptr<TcpSocketState> tcb, const TcpRateOps::TcpRateSample &rs)
{
NS_LOG_FUNCTION (this << tcb << rs);
if (tcb->m_bytesInFlight.Get () == 0U && rs.m_isAppLimited)
{
m_idleRestart = true;
if (m_state == BbrMode_t::BBR_PROBE_BW)
{
SetPacingRate (tcb, 1);
}
}
}
void
TcpBbr::SetPacingRate (Ptr<TcpSocketState> tcb, double gain)
{
NS_LOG_FUNCTION (this << tcb << gain);
DataRate rate (gain * m_maxBwFilter.GetBest ().GetBitRate ());
rate = std::min (rate, tcb->m_maxPacingRate);
if (m_isPipeFilled || rate > tcb->m_currentPacingRate)
{
tcb->m_currentPacingRate = rate;
}
}
uint32_t
TcpBbr::InFlight (Ptr<TcpSocketState> tcb, double gain)
{
NS_LOG_FUNCTION (this << tcb << gain);
if (m_rtProp == Time::Max ())
{
return tcb->m_initialCWnd * tcb->m_segmentSize;
}
double quanta = 3 * m_sendQuantum;
double estimatedBdp = m_maxBwFilter.GetBest () * m_rtProp / 8.0;
return gain * estimatedBdp + quanta;
}
void
TcpBbr::AdvanceCyclePhase ()
{
NS_LOG_FUNCTION (this);
m_cycleStamp = Simulator::Now ();
m_cycleIndex = (m_cycleIndex + 1) % GAIN_CYCLE_LENGTH;
m_pacingGain = PACING_GAIN_CYCLE [m_cycleIndex];
}
bool
TcpBbr::IsNextCyclePhase (Ptr<TcpSocketState> tcb, const TcpRateOps::TcpRateSample &rs)
{
NS_LOG_FUNCTION (this << tcb << rs);
bool isFullLength = (Simulator::Now () - m_cycleStamp) > m_rtProp;
if (m_pacingGain == 1)
{
return isFullLength;
}
else if (m_pacingGain > 1)
{
return isFullLength && (rs.m_bytesLoss > 0 || rs.m_priorInFlight >= InFlight (tcb, m_pacingGain));
}
else
{
return isFullLength || rs.m_priorInFlight <= InFlight (tcb, 1);
}
}
void
TcpBbr::CheckCyclePhase (Ptr<TcpSocketState> tcb, const TcpRateOps::TcpRateSample &rs)
{
NS_LOG_FUNCTION (this << tcb << rs);
if (m_state == BbrMode_t::BBR_PROBE_BW && IsNextCyclePhase (tcb, rs))
{
AdvanceCyclePhase ();
}
}
void
TcpBbr::CheckFullPipe (const TcpRateOps::TcpRateSample &rs)
{
NS_LOG_FUNCTION (this << rs);
if (m_isPipeFilled || !m_roundStart || rs.m_isAppLimited)
{
return;
}
/* Check if Bottleneck bandwidth is still growing*/
if (m_maxBwFilter.GetBest ().GetBitRate () >= m_fullBandwidth.GetBitRate () * 1.25)
{
m_fullBandwidth = m_maxBwFilter.GetBest ();
m_fullBandwidthCount = 0;
return;
}
m_fullBandwidthCount++;
if (m_fullBandwidthCount >= 3)
{
NS_LOG_DEBUG ("Pipe filled");
m_isPipeFilled = true;
}
}
void
TcpBbr::EnterDrain ()
{
NS_LOG_FUNCTION (this);
SetBbrState (BbrMode_t::BBR_DRAIN);
m_pacingGain = 1.0 / m_highGain;
m_cWndGain = m_highGain;
}
void
TcpBbr::EnterProbeBW ()
{
NS_LOG_FUNCTION (this);
SetBbrState (BbrMode_t::BBR_PROBE_BW);
m_pacingGain = 1;
m_cWndGain = 2;
m_cycleIndex = GAIN_CYCLE_LENGTH - 1 - (int) m_uv->GetValue (0, 6);
AdvanceCyclePhase ();
}
void
TcpBbr::CheckDrain (Ptr<TcpSocketState> tcb)
{
NS_LOG_FUNCTION (this << tcb);
if (m_state == BbrMode_t::BBR_STARTUP && m_isPipeFilled)
{
EnterDrain ();
}
if (m_state == BbrMode_t::BBR_DRAIN && tcb->m_bytesInFlight <= InFlight (tcb, 1))
{
EnterProbeBW ();
}
}
void
TcpBbr::UpdateRTprop (Ptr<TcpSocketState> tcb)
{
NS_LOG_FUNCTION (this << tcb);
m_rtPropExpired = Simulator::Now () > (m_rtPropStamp + m_rtPropFilterLen);
if (tcb->m_lastRtt >= Seconds (0) && (tcb->m_lastRtt <= m_rtProp || m_rtPropExpired))
{
m_rtProp = tcb->m_lastRtt;
m_rtPropStamp = Simulator::Now ();
}
}
void
TcpBbr::EnterProbeRTT ()
{
NS_LOG_FUNCTION (this);
SetBbrState (BbrMode_t::BBR_PROBE_RTT);
m_pacingGain = 1;
m_cWndGain = 1;
}
void
TcpBbr::SaveCwnd (Ptr<const TcpSocketState> tcb)
{
NS_LOG_FUNCTION (this << tcb);
if (tcb->m_congState != TcpSocketState::CA_RECOVERY && m_state != BbrMode_t::BBR_PROBE_RTT)
{
m_priorCwnd = tcb->m_cWnd;
}
else
{
m_priorCwnd = std::max (m_priorCwnd, tcb->m_cWnd.Get ());
}
}
void
TcpBbr::RestoreCwnd (Ptr<TcpSocketState> tcb)
{
NS_LOG_FUNCTION (this << tcb);
tcb->m_cWnd = std::max (m_priorCwnd, tcb->m_cWnd.Get ());
}
void
TcpBbr::ExitProbeRTT ()
{
NS_LOG_FUNCTION (this);
if (m_isPipeFilled)
{
EnterProbeBW ();
}
else
{
EnterStartup ();
}
}
void
TcpBbr::HandleProbeRTT (Ptr<TcpSocketState> tcb)
{
NS_LOG_FUNCTION (this << tcb);
m_appLimited = (m_delivered + tcb->m_bytesInFlight.Get ()) ? : 1;
if (m_probeRttDoneStamp == Seconds (0) && tcb->m_bytesInFlight <= m_minPipeCwnd)
{
m_probeRttDoneStamp = Simulator::Now () + m_probeRttDuration;
m_probeRttRoundDone = false;
m_nextRoundDelivered = m_delivered;
}
else if (m_probeRttDoneStamp != Seconds (0))
{
if (m_roundStart)
{
m_probeRttRoundDone = true;
}
if (m_probeRttRoundDone && Simulator::Now () > m_probeRttDoneStamp)
{
m_rtPropStamp = Simulator::Now ();
RestoreCwnd (tcb);
ExitProbeRTT ();
}
}
}
void
TcpBbr::CheckProbeRTT (Ptr<TcpSocketState> tcb)
{
NS_LOG_FUNCTION (this << tcb);
if (m_state != BbrMode_t::BBR_PROBE_RTT && m_rtPropExpired && !m_idleRestart)
{
EnterProbeRTT ();
SaveCwnd (tcb);
m_probeRttDoneStamp = Seconds (0);
}
if (m_state == BbrMode_t::BBR_PROBE_RTT)
{
HandleProbeRTT (tcb);
}
m_idleRestart = false;
}
void
TcpBbr::SetSendQuantum (Ptr<TcpSocketState> tcb)
{
NS_LOG_FUNCTION (this << tcb);
m_sendQuantum = 1 * tcb->m_segmentSize;
}
void
TcpBbr::UpdateTargetCwnd (Ptr<TcpSocketState> tcb)
{
NS_LOG_FUNCTION (this << tcb);
m_targetCWnd = InFlight (tcb, m_cWndGain);
}
void
TcpBbr::ModulateCwndForRecovery (Ptr<TcpSocketState> tcb, const TcpRateOps::TcpRateSample &rs)
{
NS_LOG_FUNCTION (this << tcb << rs);
if ( rs.m_bytesLoss > 0)
{
tcb->m_cWnd = std::max ((int) tcb->m_cWnd.Get () - (int) rs.m_bytesLoss, (int) tcb->m_segmentSize);
}
if (m_packetConservation)
{
tcb->m_cWnd = std::max (tcb->m_cWnd.Get (), tcb->m_bytesInFlight.Get () + rs.m_ackedSacked);
}
}
void
TcpBbr::ModulateCwndForProbeRTT (Ptr<TcpSocketState> tcb)
{
NS_LOG_FUNCTION (this << tcb);
if (m_state == BbrMode_t::BBR_PROBE_RTT)
{
tcb->m_cWnd = std::min (tcb->m_cWnd.Get (), m_minPipeCwnd);
}
}
void
TcpBbr::SetCwnd (Ptr<TcpSocketState> tcb, const TcpRateOps::TcpRateSample &rs)
{
NS_LOG_FUNCTION (this << tcb << rs);
UpdateTargetCwnd (tcb);
if (tcb->m_congState == TcpSocketState::CA_RECOVERY)
{
ModulateCwndForRecovery (tcb, rs);
}
if (!m_packetConservation)
{
if (m_isPipeFilled)
{
tcb->m_cWnd = std::min (tcb->m_cWnd.Get () + (uint32_t) rs.m_ackedSacked, m_targetCWnd);
}
else if (tcb->m_cWnd < m_targetCWnd || m_delivered < tcb->m_initialCWnd * tcb->m_segmentSize)
{
tcb->m_cWnd = tcb->m_cWnd.Get () + rs.m_ackedSacked;
}
tcb->m_cWnd = std::max (tcb->m_cWnd.Get (), m_minPipeCwnd);
}
ModulateCwndForProbeRTT (tcb);
if (tcb->m_congState == TcpSocketState::CA_RECOVERY)
{
m_packetConservation = false;
}
}
void
TcpBbr::UpdateRound (Ptr<TcpSocketState> tcb, const TcpRateOps::TcpRateSample &rs)
{
NS_LOG_FUNCTION (this << tcb << rs);
if (m_txItemDelivered >= m_nextRoundDelivered)
{
m_nextRoundDelivered = m_delivered;
m_roundCount++;
m_roundStart = true;
}
else
{
m_roundStart = false;
}
}
void
TcpBbr::UpdateBtlBw (Ptr<TcpSocketState> tcb, const TcpRateOps::TcpRateSample &rs)
{
NS_LOG_FUNCTION (this << tcb << rs);
if (rs.m_deliveryRate == 0)
{
return;
}
UpdateRound (tcb, rs);
if (rs.m_deliveryRate >= m_maxBwFilter.GetBest () || !rs.m_isAppLimited)
{
m_maxBwFilter.Update (rs.m_deliveryRate, m_roundCount);
}
}
void
TcpBbr::UpdateModelAndState (Ptr<TcpSocketState> tcb, const TcpRateOps::TcpRateSample &rs)
{
NS_LOG_FUNCTION (this << tcb << rs);
UpdateBtlBw (tcb, rs);
CheckCyclePhase (tcb, rs);
CheckFullPipe (rs);
CheckDrain (tcb);
UpdateRTprop (tcb);
CheckProbeRTT (tcb);
}
void
TcpBbr::UpdateControlParameters (Ptr<TcpSocketState> tcb, const TcpRateOps::TcpRateSample &rs)
{
NS_LOG_FUNCTION (this << tcb << rs);
SetPacingRate (tcb, m_pacingGain);
SetSendQuantum (tcb);
SetCwnd (tcb, rs);
}
std::string
TcpBbr::WhichState (BbrMode_t mode) const
{
switch (mode)
{
case 0:
return "BBR_STARTUP";
case 1:
return "BBR_DRAIN";
case 2:
return "BBR_PROBE_BW";
case 3:
return "BBR_PROBE_RTT";
}
NS_ASSERT (false);
}
void
TcpBbr::SetBbrState (BbrMode_t mode)
{
NS_LOG_FUNCTION (this << mode);
NS_LOG_DEBUG (Simulator::Now () << " Changing from " << WhichState (m_state) << " to " << WhichState (mode));
m_state = mode;
}
uint32_t
TcpBbr::GetBbrState ()
{
NS_LOG_FUNCTION (this);
return m_state;
}
double
TcpBbr::GetCwndGain ()
{
NS_LOG_FUNCTION (this);
return m_cWndGain;
}
double
TcpBbr::GetPacingGain ()
{
NS_LOG_FUNCTION (this);
return m_pacingGain;
}
std::string
TcpBbr::GetName () const
{
return "TcpBbr";
}
bool
TcpBbr::HasCongControl () const
{
NS_LOG_FUNCTION (this);
return true;
}
void
TcpBbr::CongControl(Ptr<TcpSocketState> tcb,
const TcpRateOps::TcpRateConnection &rc,
const TcpRateOps::TcpRateSample &rs)
{
NS_LOG_FUNCTION (this << tcb << rs);
m_delivered = rc.m_delivered;
m_txItemDelivered = rc.m_txItemDelivered;
UpdateModelAndState (tcb, rs);
UpdateControlParameters (tcb, rs);
}
void
TcpBbr::CongestionStateSet (Ptr<TcpSocketState> tcb,
const TcpSocketState::TcpCongState_t newState)
{
NS_LOG_FUNCTION (this << tcb << newState);
if (newState == TcpSocketState::CA_OPEN && !m_isInitialized)
{
NS_LOG_DEBUG ("CongestionStateSet triggered to CA_OPEN :: " << newState);
m_rtProp = tcb->m_lastRtt.Get () != Time::Max () ? tcb->m_lastRtt.Get () : Time::Max ();
m_rtPropStamp = Simulator::Now ();
m_priorCwnd = tcb->m_initialCWnd * tcb->m_segmentSize;
m_targetCWnd = tcb->m_initialCWnd * tcb->m_segmentSize;
m_minPipeCwnd = 4 * tcb->m_segmentSize;
m_sendQuantum = 1 * tcb->m_segmentSize;
m_maxBwFilter = MaxBandwidthFilter_t (m_bandwidthWindowLength,
DataRate (tcb->m_initialCWnd * tcb->m_segmentSize * 8 / m_rtProp.GetSeconds ())
, 0);
InitRoundCounting ();
InitFullPipe ();
InitPacingRate (tcb);
EnterStartup ();
m_isInitialized = true;
}
else if (newState == TcpSocketState::CA_LOSS)
{
NS_LOG_DEBUG ("CongestionStateSet triggered to CA_LOSS :: " << newState);
SaveCwnd (tcb);
m_roundStart = true;
}
else if (newState == TcpSocketState::CA_RECOVERY)
{
NS_LOG_DEBUG ("CongestionStateSet triggered to CA_RECOVERY :: " << newState);
SaveCwnd (tcb);
tcb->m_cWnd = tcb->m_bytesInFlight.Get () + std::max (tcb->m_lastAckedSackedBytes, tcb->m_segmentSize);
m_packetConservation = true;
}
}
void
TcpBbr::CwndEvent (Ptr<TcpSocketState> tcb,
const TcpSocketState::TcpCAEvent_t event)
{
NS_LOG_FUNCTION (this << tcb << event);
if (event == TcpSocketState::CA_EVENT_COMPLETE_CWR)
{
NS_LOG_DEBUG ("CwndEvent triggered to CA_EVENT_COMPLETE_CWR :: " << event);
m_packetConservation = false;
RestoreCwnd (tcb);
}
else if (event == TcpSocketState::CA_EVENT_TX_START)
{
NS_LOG_DEBUG ("CwndEvent triggered to CA_EVENT_TX_START :: " << event);
if (tcb->m_bytesInFlight.Get () == 0 && m_appLimited)
{
m_idleRestart = true;
if (m_state == BbrMode_t::BBR_PROBE_BW && m_appLimited)
{
SetPacingRate (tcb, 1);
}
}
}
}
uint32_t
TcpBbr::GetSsThresh (Ptr<const TcpSocketState> tcb, uint32_t bytesInFlight)
{
NS_LOG_FUNCTION (this << tcb << bytesInFlight);
SaveCwnd (tcb);
return tcb->m_initialSsThresh;
}
void
TcpBbr::ReduceCwnd (Ptr<TcpSocketState> tcb)
{
NS_LOG_FUNCTION (this << tcb);
}
Ptr<TcpCongestionOps>
TcpBbr::Fork (void)
{
return CopyObject<TcpBbr> (this);
}
} // namespace ns3

View File

@@ -0,0 +1,365 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2018 NITK Surathkal
*
* 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: Vivek Jain <jain.vivek.anand@gmail.com>
* Viyom Mittal <viyommittal@gmail.com>
* Mohit P. Tahiliani <tahiliani@nitk.edu.in>
*/
#ifndef TCPBBR_H
#define TCPBBR_H
#include "ns3/tcp-congestion-ops.h"
#include "ns3/traced-value.h"
#include "ns3/data-rate.h"
#include "ns3/random-variable-stream.h"
#include "ns3/windowed-filter.h"
class TcpBbrCheckGainValuesTest;
namespace ns3 {
class TcpBbr : public TcpCongestionOps
{
public:
/**
* \brief The number of phases in the BBR ProbeBW gain cycle.
*/
static const uint8_t GAIN_CYCLE_LENGTH = 8;
/**
* \brief BBR uses an eight-phase cycle with the given pacing_gain value
* in the BBR ProbeBW gain cycle.
*/
const static double PACING_GAIN_CYCLE [];
/**
* \brief Get the type ID.
* \return the object TypeId
*/
static TypeId GetTypeId (void);
/**
* \brief Constructor
*/
TcpBbr ();
/**
* Copy constructor.
* \param sock The socket to copy from.
*/
TcpBbr (const TcpBbr &sock);
/* BBR has the following modes for deciding how fast to send: */
typedef enum
{
BBR_STARTUP, /* ramp up sending rate rapidly to fill pipe */
BBR_DRAIN, /* drain any queue created during startup */
BBR_PROBE_BW, /* discover, share bw: pace around estimated bw */
BBR_PROBE_RTT, /* cut inflight to min to probe min_rtt */
} BbrMode_t;
typedef WindowedFilter<DataRate,
MaxFilter<DataRate>,
uint32_t,
uint32_t>
MaxBandwidthFilter_t;
/**
* Assign a fixed random variable stream number to the random variables
* used by this model. Return the number of streams (possibly zero) that
* have been assigned.
*
* \param stream first stream index to use
* \return the number of stream indices assigned by this model
*/
virtual int64_t AssignStreams (int64_t stream);
virtual std::string GetName () const;
virtual bool HasCongControl () const;
virtual void CongControl (Ptr<TcpSocketState> tcb,
const TcpRateOps::TcpRateConnection &rc,
const TcpRateOps::TcpRateSample &rs);
virtual void CongestionStateSet (Ptr<TcpSocketState> tcb,
const TcpSocketState::TcpCongState_t newState);
virtual void CwndEvent (Ptr<TcpSocketState> tcb,
const TcpSocketState::TcpCAEvent_t event);
virtual uint32_t GetSsThresh (Ptr<const TcpSocketState> tcb,
uint32_t bytesInFlight);
virtual void ReduceCwnd (Ptr<TcpSocketState> tcb);
virtual Ptr<TcpCongestionOps> Fork ();
protected:
/**
* \brief TcpBbrCheckGainValuesTest friend class (for tests).
* \relates TcpBbrCheckGainValuesTest
*/
friend class TcpBbrCheckGainValuesTest;
/**
* \brief Advances pacing gain using cycle gain algorithm, while in BBR_PROBE_BW state
*/
void AdvanceCyclePhase ();
/**
* \brief Checks whether to advance pacing gain in BBR_PROBE_BW state,
* and if allowed calls AdvanceCyclePhase ()
* \param tcb the socket state.
* \param rs rate sample
*/
void CheckCyclePhase (Ptr<TcpSocketState> tcb, const TcpRateOps::TcpRateSample &rs);
/**
* \brief Checks whether its time to enter BBR_DRAIN or BBR_PROBE_BW state
* \param tcb the socket state.
*/
void CheckDrain (Ptr<TcpSocketState> tcb);
/**
* \brief Identifies whether pipe or BDP is already full
* \param rs rate sample
*/
void CheckFullPipe (const TcpRateOps::TcpRateSample &rs);
/**
* \brief This method handles the steps related to the ProbeRTT state
* \param tcb the socket state.
*/
void CheckProbeRTT (Ptr<TcpSocketState> tcb);
/**
* \brief Updates variables specific to BBR_DRAIN state
*/
void EnterDrain ();
/**
* \brief Updates variables specific to BBR_PROBE_BW state
*/
void EnterProbeBW ();
/**
* \brief Updates variables specific to BBR_PROBE_RTT state
*/
void EnterProbeRTT ();
/**
* \brief Updates variables specific to BBR_STARTUP state
*/
void EnterStartup ();
/**
* \brief Called on exiting from BBR_PROBE_RTT state, it eithers invoke EnterProbeBW () or EnterStartup ()
*/
void ExitProbeRTT ();
/**
* \brief Gets BBR state.
* \return returns BBR state.
*/
uint32_t GetBbrState ();
/**
* \brief Gets current pacing gain.
* \return returns current pacing gain.
*/
double GetPacingGain ();
/**
* \brief Gets current cwnd gain.
* \return returns current cwnd gain.
*/
double GetCwndGain ();
/**
* \brief Handles the steps for BBR_PROBE_RTT state.
* \param tcb the socket state.
*/
void HandleProbeRTT (Ptr<TcpSocketState> tcb);
/**
* \brief Updates pacing rate if socket is restarting from idle state.
* \param tcb the socket state.
* \param rs rate sample
*/
void HandleRestartFromIdle (Ptr<TcpSocketState> tcb, const TcpRateOps::TcpRateSample &rs);
/**
* \brief Estimates the target value for congestion window
* \param tcb the socket state.
* \param gain cwnd gain
*/
uint32_t InFlight (Ptr<TcpSocketState> tcb, double gain);
/**
* \brief Intializes the full pipe estimator.
*/
void InitFullPipe ();
/**
* \brief Intializes the pacing rate.
* \param tcb the socket state.
*/
void InitPacingRate (Ptr<TcpSocketState> tcb);
/**
* \brief Intializes the round counting related variables.
*/
void InitRoundCounting ();
/**
* \brief Checks whether to move to next value of pacing gain while in BBR_PROBE_BW.
* \param tcb the socket state.
* \param rs rate sample
* \returns true if want to move to next value otherwise false.
*/
bool IsNextCyclePhase (Ptr<TcpSocketState> tcb, const TcpRateOps::TcpRateSample &rs);
/**
* \brief Modulates congestion window in BBR_PROBE_RTT.
* \param tcb the socket state
*/
void ModulateCwndForProbeRTT (Ptr<TcpSocketState> tcb);
/**
* \brief Modulates congestion window in CA_RECOVERY.
* \param tcb the socket state.
* \param rs rate sample
*/
void ModulateCwndForRecovery (Ptr<TcpSocketState> tcb, const TcpRateOps::TcpRateSample &rs);
/**
* \brief Helper to restore the last-known good congestion window
* \param tcb the socket state.
*/
void RestoreCwnd (Ptr<TcpSocketState> tcb);
/**
* \brief Helper to remember the last-known good congestion window or
* the latest congestion window unmodulated by loss recovery or ProbeRTT.
* \param tcb the socket state.
*/
void SaveCwnd (Ptr<const TcpSocketState> tcb);
/**
* \brief Updates congestion window based on the network model.
* \param tcb the socket state.
* \param rs rate sample
*/
void SetCwnd (Ptr<TcpSocketState> tcb, const TcpRateOps::TcpRateSample &rs);
/**
* \brief Updates pacing rate based on network model.
* \param tcb the socket state.
* \param gain pacing gain
*/
void SetPacingRate (Ptr<TcpSocketState> tcb, double gain);
/**
* \brief Updates send quantum based on the network model.
* \param tcb the socket state.
*/
void SetSendQuantum (Ptr<TcpSocketState> tcb);
/**
* \brief Updates maximum bottleneck.
* \param tcb the socket state.
* \param rs rate sample
*/
void UpdateBtlBw (Ptr<TcpSocketState> tcb, const TcpRateOps::TcpRateSample &rs);
/**
* \brief Updates control parameters congestion windowm, pacing rate, send quantum.
* \param tcb the socket state.
* \param rs rate sample
*/
void UpdateControlParameters (Ptr<TcpSocketState> tcb, const TcpRateOps::TcpRateSample &rs);
/**
* \brief Updates BBR network model (Maximum bandwidth and minimum RTT).
* \param tcb the socket state.
* \param rs rate sample
*/
void UpdateModelAndState (Ptr<TcpSocketState> tcb, const TcpRateOps::TcpRateSample &rs);
/**
* \brief Updates round counting related variables.
* \param tcb the socket state.
* \param rs rate sample
*/
void UpdateRound (Ptr<TcpSocketState> tcb, const TcpRateOps::TcpRateSample &rs);
/**
* \brief Updates minimum RTT.
* \param tcb the socket state.
*/
void UpdateRTprop (Ptr<TcpSocketState> tcb);
/**
* \brief Updates target congestion window.
* \param tcb the socket state.
*/
void UpdateTargetCwnd (Ptr<TcpSocketState> tcb);
/**
* \brief Sets BBR state.
* \param state BBR state.
*/
void SetBbrState (BbrMode_t state);
/**
* \brief Maps mode into string.
* \return string translation of mode value.
*/
std::string WhichState (BbrMode_t state) const;
private:
BbrMode_t m_state {BbrMode_t::BBR_STARTUP}; //!< Current state of BBR state machine
MaxBandwidthFilter_t m_maxBwFilter; //!< Maximum bandwidth filter
uint32_t m_bandwidthWindowLength {0}; //!< A constant specifying the length of the BBR.BtlBw max filter window, default 10 packet-timed round trips.
double m_pacingGain {0}; //!< The dynamic pacing gain factor
double m_cWndGain {0}; //!< The dynamic congestion window gain factor
double m_highGain {0}; //!< A constant specifying highest gain factor, default is 2.89
bool m_isPipeFilled {false}; //!< A boolean that records whether BBR has filled the pipe
uint32_t m_minPipeCwnd {0}; //!< The minimal congestion window value BBR tries to target, default 4 Segment size
uint32_t m_roundCount {0}; //!< Count of packet-timed round trips
bool m_roundStart {false}; //!< A boolean that BBR sets to true once per packet-timed round trip
uint32_t m_nextRoundDelivered {0}; //!< Denotes the end of a packet-timed round trip
Time m_probeRttDuration {MilliSeconds (200)};//!< A constant specifying the minimum duration for which ProbeRTT state, default 200 millisecs
Time m_probeRtPropStamp {Seconds (0)}; //!< The wall clock time at which the current BBR.RTProp sample was obtained.
Time m_probeRttDoneStamp {Seconds (0)}; //!< Time to exit from BBR_PROBE_RTT state
bool m_probeRttRoundDone {false}; //!< True when it is time to exit BBR_PROBE_RTT
bool m_packetConservation {false}; //!<
uint32_t m_priorCwnd {0}; //!< The last-known good congestion window
bool m_idleRestart {false}; //!< When restarting from idle, set it true
uint32_t m_targetCWnd {0}; //!< Target value for congestion window, adapted to the estimated BDP
DataRate m_fullBandwidth {0}; //!< Value of full bandwidth recorded
uint32_t m_fullBandwidthCount {0}; //!< Count of full bandwidth recorded consistently
Time m_rtProp {Time::Max ()}; //!< Estimated two-way round-trip propagation delay of the path, estimated from the windowed minimum recent round-trip delay sample.
uint32_t m_sendQuantum {0}; //!< The maximum size of a data aggregate scheduled and transmitted together
Time m_cycleStamp {Seconds (0)}; //!< Last time gain cycle updated
uint32_t m_cycleIndex {0}; //!< Current index of gain cycle
bool m_rtPropExpired {false}; //!< A boolean recording whether the BBR.RTprop has expired
Time m_rtPropFilterLen {Seconds (10)}; //!< A constant specifying the length of the RTProp min filter window, default 10 secs.
Time m_rtPropStamp {Seconds (0)}; //!< The wall clock time at which the current BBR.RTProp sample was obtained
bool m_isInitialized {false}; //!< Set to true after first time initializtion variables
Ptr<UniformRandomVariable> m_uv {nullptr}; //!< Uniform Random Variable
uint64_t m_delivered {0}; //!< The total amount of data in bytes delivered so far
uint32_t m_appLimited {0}; //!< The index of the last transmitted packet marked as application-limited
uint32_t m_txItemDelivered {0};
};
} // namespace ns3
#endif // TCPBBR_H

View File

@@ -1811,6 +1811,7 @@ TcpSocketBase::ReceivedAck (Ptr<Packet> packet, const TcpHeader& tcpHeader)
m_txBuffer->DiscardUpTo (ackNumber, MakeCallback (&TcpRateOps::SkbDelivered, m_rateOps));
uint32_t currentDelivered = static_cast<uint32_t> (m_rateOps->GetConnectionRate ().m_delivered - previousDelivered);
m_tcb->m_lastAckedSackedBytes = currentDelivered;
if (m_tcb->m_congState == TcpSocketState::CA_CWR && (ackNumber > m_recover))
{

View File

@@ -116,7 +116,10 @@ TcpSocketState::TcpSocketState (const TcpSocketState &other)
m_bytesInFlight (other.m_bytesInFlight),
m_lastRtt (other.m_lastRtt),
m_ecnMode (other.m_ecnMode),
m_useEcn (other.m_useEcn)
m_useEcn (other.m_useEcn),
m_ectCodePoint (other.m_ectCodePoint),
m_lastAckedSackedBytes (other.m_lastAckedSackedBytes)
{
}

View File

@@ -207,6 +207,8 @@ public:
EcnCodePoint_t m_ectCodePoint {Ect0}; //!< ECT code point to use
uint32_t m_lastAckedSackedBytes {0}; //!< Last acked and sacked recorded upon receiving last acknowledgment
/**
* \brief Get cwnd in segments rather than bytes
*

View File

@@ -163,6 +163,7 @@ def build(bld):
'model/tcp-htcp.cc',
'model/tcp-lp.cc',
'model/tcp-dctcp.cc',
'model/tcp-bbr.cc',
'model/tcp-rx-buffer.cc',
'model/tcp-tx-buffer.cc',
'model/tcp-tx-item.cc',
@@ -421,6 +422,7 @@ def build(bld):
'model/tcp-lp.h',
'model/tcp-dctcp.h',
'model/windowed-filter.h',
'model/tcp-bbr.h',
'model/tcp-ledbat.h',
'model/tcp-socket-base.h',
'model/tcp-socket-state.h',