| /* -*- 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 |