blob: b0d2b836bee3ce5b04d6a1f88d3743c5ce9530ab [file] [log] [blame]
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
//
// Copyright (c) 2006 Georgia Tech Research Corporation
//
// 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
//
// Author: Rajib Bhattacharjea<raj.b@gatech.edu>
//
// THIS IS A COPY OF rtt-estimator.cc from internet module with minor modifications
// Ported from:
// Georgia Tech Network Simulator - Round Trip Time Estimation Class
// George F. Riley. Georgia Tech, Spring 2002
// Implements several variations of round trip time estimators
#include <iostream>
#include "ndn-rtt-estimator.h"
#include "ns3/simulator.h"
#include "ns3/double.h"
#include "ns3/integer.h"
#include "ns3/uinteger.h"
#include "ns3/log.h"
NS_LOG_COMPONENT_DEFINE ("ndn.RttEstimator");
namespace ns3 {
namespace ndn {
NS_OBJECT_ENSURE_REGISTERED (RttEstimator);
TypeId
RttEstimator::GetTypeId (void)
{
static TypeId tid = TypeId ("ns3::ndn::RttEstimator")
.SetParent<Object> ()
.AddAttribute ("MaxMultiplier",
"Maximum RTO Multiplier",
UintegerValue (64),
MakeUintegerAccessor (&RttEstimator::m_maxMultiplier),
MakeUintegerChecker<uint16_t> ())
.AddAttribute ("InitialEstimation",
"Initial RTT estimation",
TimeValue (Seconds (1.0)),
MakeTimeAccessor (&RttEstimator::m_initialEstimatedRtt),
MakeTimeChecker ())
.AddAttribute ("MinRTO",
"Minimum retransmit timeout value",
TimeValue (Seconds (0.2)), // RFC2988 says min RTO=1 sec, but Linux uses 200ms. See http://www.postel.org/pipermail/end2end-interest/2004-November/004402.html
MakeTimeAccessor (&RttEstimator::SetMinRto,
&RttEstimator::GetMinRto),
MakeTimeChecker ())
.AddAttribute ("MaxRTO",
"Maximum retransmit timeout value",
TimeValue (Seconds (200.0)),
MakeTimeAccessor (&RttEstimator::SetMaxRto,
&RttEstimator::GetMaxRto),
MakeTimeChecker ())
;
return tid;
}
void
RttEstimator::SetMinRto (Time minRto)
{
NS_LOG_FUNCTION (this << minRto);
m_minRto = minRto;
}
Time
RttEstimator::GetMinRto (void) const
{
return m_minRto;
}
void
RttEstimator::SetMaxRto (Time maxRto)
{
NS_LOG_FUNCTION (this << maxRto);
m_maxRto = maxRto;
}
Time
RttEstimator::GetMaxRto (void) const
{
return m_maxRto;
}
void
RttEstimator::SetCurrentEstimate (Time estimate)
{
NS_LOG_FUNCTION (this << estimate);
m_currentEstimatedRtt = estimate;
}
Time
RttEstimator::GetCurrentEstimate (void) const
{
return m_currentEstimatedRtt;
}
//RttHistory methods
RttHistory::RttHistory (SequenceNumber32 s, uint32_t c, Time t)
: seq (s), count (c), time (t), retx (false)
{
NS_LOG_FUNCTION (this);
}
RttHistory::RttHistory (const RttHistory& h)
: seq (h.seq), count (h.count), time (h.time), retx (h.retx)
{
NS_LOG_FUNCTION (this);
}
// Base class methods
RttEstimator::RttEstimator ()
: m_next (1),
m_nSamples (0),
m_multiplier (1),
m_history ()
{
NS_LOG_FUNCTION (this);
//note next=1 everywhere since first segment will have sequence 1
// We need attributes initialized here, not later, so use the
// ConstructSelf() technique documented in the manual
ObjectBase::ConstructSelf (AttributeConstructionList ());
m_currentEstimatedRtt = m_initialEstimatedRtt;
NS_LOG_DEBUG ("Initialize m_currentEstimatedRtt to " << m_currentEstimatedRtt.GetSeconds () << " sec.");
}
RttEstimator::RttEstimator (const RttEstimator& c)
: Object (c), m_next (c.m_next),
m_maxMultiplier (c.m_maxMultiplier),
m_initialEstimatedRtt (c.m_initialEstimatedRtt),
m_currentEstimatedRtt (c.m_currentEstimatedRtt), m_minRto (c.m_minRto), m_maxRto (c.m_maxRto),
m_nSamples (c.m_nSamples), m_multiplier (c.m_multiplier),
m_history (c.m_history)
{
NS_LOG_FUNCTION (this);
}
RttEstimator::~RttEstimator ()
{
NS_LOG_FUNCTION (this);
}
TypeId
RttEstimator::GetInstanceTypeId (void) const
{
return GetTypeId ();
}
void RttEstimator::SentSeq (SequenceNumber32 seq, uint32_t size)
{
NS_LOG_FUNCTION (this << seq << size);
// Note that a particular sequence has been sent
if (seq == m_next)
{ // This is the next expected one, just log at end
m_history.push_back (RttHistory (seq, size, Simulator::Now () ));
m_next = seq + SequenceNumber32 (size); // Update next expected
}
else
{ // This is a retransmit, find in list and mark as re-tx
for (RttHistory_t::iterator i = m_history.begin (); i != m_history.end (); ++i)
{
if ((seq >= i->seq) && (seq < (i->seq + SequenceNumber32 (i->count))))
{ // Found it
i->retx = true;
// One final test..be sure this re-tx does not extend "next"
if ((seq + SequenceNumber32 (size)) > m_next)
{
m_next = seq + SequenceNumber32 (size);
i->count = ((seq + SequenceNumber32 (size)) - i->seq); // And update count in hist
}
break;
}
}
}
}
Time RttEstimator::AckSeq (SequenceNumber32 ackSeq)
{
NS_LOG_FUNCTION (this << ackSeq);
// An ack has been received, calculate rtt and log this measurement
// Note we use a linear search (O(n)) for this since for the common
// case the ack'ed packet will be at the head of the list
Time m = Seconds (0.0);
if (m_history.size () == 0) return (m); // No pending history, just exit
RttHistory& h = m_history.front ();
if (!h.retx && ackSeq >= (h.seq + SequenceNumber32 (h.count)))
{ // Ok to use this sample
m = Simulator::Now () - h.time; // Elapsed time
Measurement (m); // Log the measurement
ResetMultiplier (); // Reset multiplier on valid measurement
}
// Now delete all ack history with seq <= ack
while(m_history.size () > 0)
{
RttHistory& h = m_history.front ();
if ((h.seq + SequenceNumber32 (h.count)) > ackSeq) break; // Done removing
m_history.pop_front (); // Remove
}
return m;
}
void RttEstimator::ClearSent ()
{
NS_LOG_FUNCTION (this);
// Clear all history entries
m_next = 1;
m_history.clear ();
}
void RttEstimator::IncreaseMultiplier ()
{
NS_LOG_FUNCTION (this);
m_multiplier = (m_multiplier*2 < m_maxMultiplier) ? m_multiplier*2 : m_maxMultiplier;
NS_LOG_DEBUG ("Multiplier increased to " << m_multiplier);
}
void RttEstimator::ResetMultiplier ()
{
NS_LOG_FUNCTION (this);
m_multiplier = 1;
}
void RttEstimator::Reset ()
{
NS_LOG_FUNCTION (this);
// Reset to initial state
m_next = 1;
m_currentEstimatedRtt = m_initialEstimatedRtt;
m_history.clear (); // Remove all info from the history
m_nSamples = 0;
ResetMultiplier ();
}
} // namespace ndn
} // namespace ns3