From 9eea4883385238dca9d816412c4a7b39ffc211fb Mon Sep 17 00:00:00 2001 From: Charitha Sangaraju Date: Fri, 19 Jan 2018 16:48:07 +0100 Subject: [PATCH] tcp: Added TCP LP --- RELEASE_NOTES | 1 + examples/tcp/tcp-variants-comparison.cc | 3 +- src/internet/doc/tcp.rst | 28 +++ src/internet/model/tcp-lp.cc | 237 +++++++++++++++++++++++ src/internet/model/tcp-lp.h | 122 ++++++++++++ src/internet/test/tcp-lp-test.cc | 239 ++++++++++++++++++++++++ src/internet/wscript | 3 + 7 files changed, 632 insertions(+), 1 deletion(-) create mode 100644 src/internet/model/tcp-lp.cc create mode 100644 src/internet/model/tcp-lp.h create mode 100644 src/internet/test/tcp-lp-test.cc diff --git a/RELEASE_NOTES b/RELEASE_NOTES index 883c2455a..9f4bf9dd8 100644 --- a/RELEASE_NOTES +++ b/RELEASE_NOTES @@ -25,6 +25,7 @@ This release has been tested on the following platforms: New user-visible features ------------------------- +- (tcp) Added TCP-LP as congestion control module - (lr-wpan) Extended addressing mode is now supported. - (tcp) Implemented the core functionality of TCP Pacing. - (internet) Ipv[4,6]AddressGenerator can now check if an address or a network is allocated. diff --git a/examples/tcp/tcp-variants-comparison.cc b/examples/tcp/tcp-variants-comparison.cc index 8c2df5aa7..861a9f6fc 100644 --- a/examples/tcp/tcp-variants-comparison.cc +++ b/examples/tcp/tcp-variants-comparison.cc @@ -225,7 +225,8 @@ int main (int argc, char *argv[]) CommandLine cmd; cmd.AddValue ("transport_prot", "Transport protocol to use: TcpNewReno, " "TcpHybla, TcpHighSpeed, TcpHtcp, TcpVegas, TcpScalable, TcpVeno, " - "TcpBic, TcpYeah, TcpIllinois, TcpWestwood, TcpWestwoodPlus, TcpLedbat ", transport_prot); + "TcpBic, TcpYeah, TcpIllinois, TcpWestwood, TcpWestwoodPlus, TcpLedbat, " + "TcpLp", transport_prot); cmd.AddValue ("error_p", "Packet error rate", error_p); cmd.AddValue ("bandwidth", "Bottleneck bandwidth", bandwidth); cmd.AddValue ("delay", "Bottleneck delay", delay); diff --git a/src/internet/doc/tcp.rst b/src/internet/doc/tcp.rst index b3d82ad07..707415232 100644 --- a/src/internet/doc/tcp.rst +++ b/src/internet/doc/tcp.rst @@ -733,6 +733,33 @@ implementation are: More information about LEDBAT is available in RFC 6817: https://tools.ietf.org/html/rfc6817 +TCP-LP +^^^^^^ + +TCP-Low priority is a delay based congestion control protocol in which the low +priority data utilizes only the excess bandwidth available on an end-to-end path. +TCP-LP uses one way delay measurements as an indicator of congestion as it does +not influence cross-traffic in the reverse direction. + +On acknowledgement: + +.. math:: + + One way delay = Receiver timestamp - Receiver timestamp echo reply + Smoothed one way delay = 7/8 * Old Smoothed one way delay + 1/8 * one way delay + If smoothed one way delay > owdMin + 15 * (owdMax - owdMin) / 100 + if LP_WITHIN_INF + cwnd = 1 + else + cwnd = cwnd / 2 + Inference timer is set + +where owdMin and owdMax are the minimum and maximum one way delays experienced +throughout the connection, LP_WITHIN_INF indicates if TCP-LP is in inference +phase or not + +More information (paper): http://cs.northwestern.edu/~akuzma/rice/doc/TCP-LP.pdf + Validation ++++++++++ @@ -759,6 +786,7 @@ section below on :ref:`Writing-tcp-tests`. * **tcp-yeah-test:** Unit tests on the YeAH congestion control * **tcp-illinois-test:** Unit tests on the Illinois congestion control * **tcp-ledbat-test:** Unit tests on the LEDBAT congestion control +* **tcp-lp-test:** Unit tests on the TCP-LP congestion control * **tcp-option:** Unit tests on TCP options * **tcp-pkts-acked-test:** Unit test the number of time that PktsAcked is called * **tcp-rto-test:** Unit test behavior after a RTO timeout occurs diff --git a/src/internet/model/tcp-lp.cc b/src/internet/model/tcp-lp.cc new file mode 100644 index 000000000..9b4e202b6 --- /dev/null +++ b/src/internet/model/tcp-lp.cc @@ -0,0 +1,237 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2016 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: Charitha Sangaraju + * Nandita G + * Mohit P. Tahiliani + * + */ + +#include "tcp-lp.h" +#include "ns3/tcp-socket-base.h" +#include "ns3/log.h" + +namespace ns3 { + +NS_LOG_COMPONENT_DEFINE ("TcpLp"); +NS_OBJECT_ENSURE_REGISTERED (TcpLp); + +TypeId +TcpLp::GetTypeId (void) +{ + static TypeId tid = TypeId ("ns3::TcpLp") + .SetParent () + .AddConstructor () + .SetGroupName ("Internet") + ; + return tid; +} + +TcpLp::TcpLp (void) + : TcpNewReno (), + m_flag (0), + m_sOwd (0), + m_owdMin (0xffffffff), + m_owdMax (0), + m_owdMaxRsv (0), + m_lastDrop (Time (0)), + m_inference (Time (0)) +{ + NS_LOG_FUNCTION (this); +} + +TcpLp::TcpLp (const TcpLp& sock) + : TcpNewReno (sock), + m_flag (sock.m_flag), + m_sOwd (sock.m_sOwd), + m_owdMin (sock.m_owdMin), + m_owdMax (sock.m_owdMax), + m_owdMaxRsv (sock.m_owdMaxRsv), + m_lastDrop (sock.m_lastDrop), + m_inference (sock.m_inference) +{ + NS_LOG_FUNCTION (this); +} + +TcpLp::~TcpLp (void) +{ + NS_LOG_FUNCTION (this); +} + +Ptr +TcpLp::Fork (void) +{ + return CopyObject (this); +} + +void +TcpLp::CongestionAvoidance (Ptr tcb, uint32_t segmentsAcked) +{ + NS_LOG_FUNCTION (this << tcb << segmentsAcked); + + if (!(m_flag & LP_WITHIN_INF)) + { + TcpNewReno::CongestionAvoidance (tcb, segmentsAcked); + } +} + +uint32_t +TcpLp::OwdCalculator (Ptr tcb) +{ + NS_LOG_FUNCTION (this << tcb); + + int64_t owd = 0; + + owd = tcb->m_rcvTimestampValue - tcb->m_rcvTimestampEchoReply; + + if (owd < 0) + { + owd = -owd; + } + if (owd > 0) + { + m_flag |= LP_VALID_OWD; + } + else + { + m_flag &= ~LP_VALID_OWD; + } + return owd; +} + +void +TcpLp::RttSample (Ptr tcb) +{ + NS_LOG_FUNCTION (this << tcb ); + + uint32_t mowd = OwdCalculator (tcb); + + if (!(m_flag & LP_VALID_OWD)) + { + return; + } + + /* record the next minimum owd */ + if (mowd < m_owdMin) + { + m_owdMin = mowd; + } + + if (mowd > m_owdMax) + { + if (mowd > m_owdMaxRsv) + { + if (m_owdMaxRsv == 0) + { + m_owdMax = mowd; + } + else + { + m_owdMax = m_owdMaxRsv; + } + m_owdMaxRsv = mowd; + } + else + { + m_owdMax = mowd; + } + } + + /* Calculation for Smoothed Owd */ + if (m_sOwd != 0) + { + mowd -= m_sOwd >> 3; + m_sOwd += mowd; /* owd = 7/8 owd + 1/8 new owd */ + } + else + { + m_sOwd = mowd << 3; /* owd = 1/8 new owd */ + } +} + +void +TcpLp::PktsAcked (Ptr tcb, uint32_t segmentsAcked, + const Time &rtt) +{ + NS_LOG_FUNCTION (this << tcb << segmentsAcked << rtt); + + if (!rtt.IsZero ()) + { + RttSample (tcb); + } + + Time timestamp = Simulator::Now (); + /* Calculation of inference time */ + if (timestamp.GetMilliSeconds () > tcb->m_rcvTimestampEchoReply) + { + m_inference = 3 * (timestamp - MilliSeconds (tcb->m_rcvTimestampEchoReply)); + } + + /* Test if within inference */ + if (!m_lastDrop.IsZero () && (timestamp - m_lastDrop < m_inference)) + { + m_flag |= LP_WITHIN_INF; + } + else + { + m_flag &= ~LP_WITHIN_INF; + } + + /* Test if within threshold */ + if (m_sOwd >> 3 <= + m_owdMin + 15 * (m_owdMax - m_owdMin) / 100) + { + m_flag |= LP_WITHIN_THR; + } + else + { + m_flag &= ~LP_WITHIN_THR; + } + + if (m_flag & LP_WITHIN_THR) + { + return; + } + + m_owdMin = m_sOwd >> 3; + m_owdMax = m_sOwd >> 2; + m_owdMaxRsv = m_sOwd >> 2; + + /* happened within inference + * drop congestion window to 1 */ + if (m_flag & LP_WITHIN_INF) + { + tcb->m_cWnd = 1U * tcb->m_segmentSize; + } + + /* happened after inference + * cut congestion window to half */ + else + { + tcb->m_cWnd = std::max (tcb->m_cWnd.Get () >> 1U, 1U * tcb->m_segmentSize); + } + + /* record this time of reduction of cwnd */ + m_lastDrop = timestamp; +} + +std::string +TcpLp::GetName () const +{ + return "TcpLp"; +} +} // namespace ns3 diff --git a/src/internet/model/tcp-lp.h b/src/internet/model/tcp-lp.h new file mode 100644 index 000000000..8924af01f --- /dev/null +++ b/src/internet/model/tcp-lp.h @@ -0,0 +1,122 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2016 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: Charitha Sangaraju + * Nandita G + * Mohit P. Tahiliani + * + */ + +#ifndef TCPLP_H +#define TCPLP_H + +#include "ns3/tcp-congestion-ops.h" +#include "ns3/traced-value.h" + +namespace ns3 { + +class TcpLp : public TcpNewReno +{ +public: + /** + * \brief Get the type ID. + * + * \return the object TypeId + */ + static TypeId GetTypeId (void); + + /** + * \brief Creates an unbound tcp socket. + * + */ + TcpLp (void); + + /** + * \brief Copy constructor + * + * \param sock the object to copy + */ + TcpLp (const TcpLp& sock); + + virtual ~TcpLp (void); + + /** + * \brief Timing information on received ACK + * + * The function is called every time an ACK is received. + * It determines the state of TcpLp and adjusts the congestion window accordingly. + * + * \param tcb internal congestion state + * \param segmentsAcked count of segments acked + * \param rtt last rtt + */ + virtual void PktsAcked (Ptr tcb, uint32_t segmentsAcked, + const Time& rtt); + + virtual std::string GetName () const; + + virtual Ptr Fork (); + +protected: + /** + * \brief Invokes Congestion Avoidance of TcpNewReno if TcpLp is not within inference. + * + * \param tcb internal congestion state + * \param segmentsAcked count of segments acked + */ + virtual void CongestionAvoidance (Ptr tcb, uint32_t segmentsAcked); + +private: + /** + * \brief Describes the state of TcpLp. + * + */ + enum State + { + LP_VALID_OWD = (1 << 1), /**< Calculated One-Way Delay is valid */ + LP_WITHIN_THR = (1 << 3), /**< TcpLp is within Threshold */ + LP_WITHIN_INF = (1 << 4), /**< TcpLp is within Inference */ + }; + + uint32_t m_flag; //! tcb); + + /** + * \brief Estimates minimum and maximum One-Way Delays and calculates the smoothed One-Way Delay. + * + * \param tcb internal congestion state + */ + void RttSample (Ptr tcb); +}; + +} // namespace ns3 + +#endif // TCPLP_H diff --git a/src/internet/test/tcp-lp-test.cc b/src/internet/test/tcp-lp-test.cc new file mode 100644 index 000000000..7f7fc86d4 --- /dev/null +++ b/src/internet/test/tcp-lp-test.cc @@ -0,0 +1,239 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2016 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: Charitha Sangaraju + * Nandita G + * Mohit P. Tahiliani + * + */ + +#include "ns3/test.h" +#include "ns3/log.h" +#include "ns3/tcp-congestion-ops.h" +#include "ns3/tcp-socket-base.h" +#include "ns3/tcp-lp.h" + +namespace ns3 { + +NS_LOG_COMPONENT_DEFINE ("TcpLpTestSuite"); + +/** + * \brief Testing the behaviour common to New Reno + */ +class TcpLpToNewReno : public TestCase +{ +public: + TcpLpToNewReno (uint32_t cWnd, uint32_t segmentSize, + uint32_t segmentsAcked,uint32_t ssThresh, Time rtt, const std::string &name); + +private: + virtual void DoRun (void); + void ExecuteTest (void); + uint32_t m_cWnd; + uint32_t m_segmentSize; + uint32_t m_ssThresh; + uint32_t m_segmentsAcked; + Time m_rtt; + Ptr m_state; +}; + +TcpLpToNewReno::TcpLpToNewReno (uint32_t cWnd, uint32_t segmentSize, + uint32_t segmentsAcked, uint32_t ssThresh, Time rtt, const std::string &name) + : TestCase (name), + m_cWnd (cWnd), + m_segmentSize (segmentSize), + m_ssThresh (ssThresh), + m_segmentsAcked (segmentsAcked), + m_rtt (rtt) +{ +} + +void +TcpLpToNewReno::DoRun () +{ + Simulator::Schedule (Seconds (0.0), &TcpLpToNewReno::ExecuteTest, this); + Simulator::Run (); + Simulator::Destroy (); +} + +void +TcpLpToNewReno::ExecuteTest () +{ + m_state = CreateObject (); + m_state->m_cWnd = m_cWnd; + m_state->m_ssThresh = m_ssThresh; + m_state->m_segmentSize = m_segmentSize; + + Ptr state = CreateObject (); + state->m_cWnd = m_cWnd; + state->m_ssThresh = m_ssThresh; + state->m_segmentSize = m_segmentSize; + + Ptr cong = CreateObject (); + + m_state->m_rcvTimestampValue = 2; + m_state->m_rcvTimestampEchoReply = 1; + + cong->PktsAcked (m_state, m_segmentsAcked, m_rtt); + cong->IncreaseWindow (m_state, m_segmentsAcked); + + Ptr NewRenoCong = CreateObject (); + NewRenoCong->IncreaseWindow (state, m_segmentsAcked); + + NS_TEST_ASSERT_MSG_EQ (m_state->m_cWnd.Get (), state->m_cWnd.Get (), + "cWnd has not updated correctly"); +} +/** + * \brief Testing TcpLp when owd exceeds threshold + */ + +class TcpLpInferenceTest1 : public TestCase +{ +public: + TcpLpInferenceTest1 (uint32_t cWnd, uint32_t segmentSize, + uint32_t segmentsAcked, Time rtt, const std::string &name); + +private: + virtual void DoRun (void); + void ExecuteTest (void); + + uint32_t m_cWnd; + uint32_t m_segmentSize; + uint32_t m_segmentsAcked; + Time m_rtt; + Ptr m_state; +}; + +TcpLpInferenceTest1::TcpLpInferenceTest1 (uint32_t cWnd, uint32_t segmentSize, + uint32_t segmentsAcked, Time rtt, const std::string &name) + : TestCase (name), + m_cWnd (cWnd), + m_segmentSize (segmentSize), + m_segmentsAcked (segmentsAcked), + m_rtt (rtt) +{ +} + +void +TcpLpInferenceTest1::DoRun () +{ + Simulator::Schedule (Seconds (0.0), &TcpLpInferenceTest1::ExecuteTest, this); + Simulator::Run (); + Simulator::Destroy (); +} + +void +TcpLpInferenceTest1::ExecuteTest () +{ + m_state = CreateObject (); + m_state->m_cWnd = m_cWnd; + m_state->m_segmentSize = m_segmentSize; + + Ptr cong = CreateObject (); + + m_state->m_rcvTimestampValue = 2; + m_state->m_rcvTimestampEchoReply = 1; + + cong->PktsAcked (m_state, m_segmentsAcked, m_rtt); + + m_state->m_rcvTimestampValue = 14; + m_state->m_rcvTimestampEchoReply = 4; + cong->PktsAcked (m_state, m_segmentsAcked, m_rtt); + + m_cWnd = m_cWnd / 2; + NS_TEST_ASSERT_MSG_EQ (m_state->m_cWnd.Get (), m_cWnd, + "cWnd has not updated correctly"); +} + +/** + * \brief Testing TcpLp when it is inference phase + */ +class TcpLpInferenceTest2 : public TestCase +{ +public: + TcpLpInferenceTest2 (uint32_t cWnd, uint32_t segmentSize, + uint32_t segmentsAcked, Time rtt, const std::string &name); + +private: + virtual void DoRun (void); + void ExecuteTest (void); + + uint32_t m_cWnd; + uint32_t m_segmentSize; + uint32_t m_segmentsAcked; + Time m_rtt; + Ptr m_state; +}; + +TcpLpInferenceTest2::TcpLpInferenceTest2 (uint32_t cWnd, uint32_t segmentSize,uint32_t segmentsAcked, Time rtt, const std::string &name) + : TestCase (name), + m_cWnd (cWnd), + m_segmentSize (segmentSize), + m_segmentsAcked (segmentsAcked), + m_rtt (rtt) +{ +} + +void +TcpLpInferenceTest2::DoRun () +{ + Simulator::Schedule (Seconds (0.0), &TcpLpInferenceTest2::ExecuteTest, this); + Simulator::Run (); + Simulator::Destroy (); +} + +void +TcpLpInferenceTest2::ExecuteTest () +{ + m_state = CreateObject (); + m_state->m_cWnd = m_cWnd; + m_state->m_segmentSize = m_segmentSize; + + Ptr cong = CreateObject (); + + m_state->m_rcvTimestampValue = 2; + m_state->m_rcvTimestampEchoReply = 1; + cong->PktsAcked (m_state, m_segmentsAcked, m_rtt); + + m_state->m_rcvTimestampValue = 14; + m_state->m_rcvTimestampEchoReply = 4; + cong->PktsAcked (m_state, m_segmentsAcked, m_rtt); + + m_state->m_rcvTimestampValue = 25; + m_state->m_rcvTimestampEchoReply = 15; + cong->PktsAcked (m_state, m_segmentsAcked, m_rtt); + + m_cWnd = 1U * m_segmentSize; + + NS_TEST_ASSERT_MSG_EQ (m_state->m_cWnd.Get (), m_cWnd, + "cWnd has not updated correctly"); +} + +static class TcpLpTestSuite : public TestSuite +{ +public: + TcpLpTestSuite () : TestSuite ("tcp-lp-test", UNIT) + { + AddTestCase (new TcpLpToNewReno (4 * 1446, 1446,2, 2 * 1446, MilliSeconds (100), "LP falls to New Reno if the owd is within threshold"), TestCase::QUICK); + + AddTestCase (new TcpLpInferenceTest1 (2 * 1446, 1446,2, MilliSeconds (100), "LP enters Inference phase when owd exceeds threshold for the first time"), TestCase::QUICK); + + AddTestCase (new TcpLpInferenceTest2 (2 * 1446, 1446,2, MilliSeconds (100), "LP reduces cWnd to 1 if owd exceeds threshold in inference phase"), TestCase::QUICK); + } +} g_tcplpTest; + +} diff --git a/src/internet/wscript b/src/internet/wscript index c875a9399..b27427c81 100644 --- a/src/internet/wscript +++ b/src/internet/wscript @@ -157,6 +157,7 @@ def build(bld): 'model/tcp-ledbat.cc', 'model/tcp-illinois.cc', 'model/tcp-htcp.cc', + 'model/tcp-lp.cc', 'model/tcp-rx-buffer.cc', 'model/tcp-tx-buffer.cc', 'model/tcp-option.cc', @@ -264,6 +265,7 @@ def build(bld): 'test/tcp-yeah-test.cc', 'test/tcp-illinois-test.cc', 'test/tcp-htcp-test.cc', + 'test/tcp-lp-test.cc', 'test/tcp-ledbat-test.cc', 'test/tcp-zero-window-test.cc', 'test/tcp-pkts-acked-test.cc', @@ -382,6 +384,7 @@ def build(bld): 'model/tcp-yeah.h', 'model/tcp-illinois.h', 'model/tcp-htcp.h', + 'model/tcp-lp.h', 'model/tcp-ledbat.h', 'model/tcp-socket-base.h', 'model/tcp-tx-buffer.h',