Issue #25 Replacing usage of TCP RTT estimator with a customized version
In the current commit, RTT estimator does not implement Karn's algorithm
and takes into account all RTT samples, including ambiguous samples from
retransmitted Interests.
diff --git a/utils/ndn-rtt-estimator.cc b/utils/ndn-rtt-estimator.cc
new file mode 100644
index 0000000..93193d2
--- /dev/null
+++ b/utils/ndn-rtt-estimator.cc
@@ -0,0 +1,248 @@
+/* -*- 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);
+}
+
+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