blob: 376c4ab9261c02c446952e0382a0c9039a754521 [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.hpp"
#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