tcp: Added TCP LP

This commit is contained in:
Charitha Sangaraju
2018-01-19 16:48:07 +01:00
parent 4e27c5e008
commit 9eea488338
7 changed files with 632 additions and 1 deletions

View File

@@ -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.

View File

@@ -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);

View File

@@ -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

View File

@@ -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 <charitha29193@gmail.com>
* Nandita G <gm.nandita@gmail.com>
* Mohit P. Tahiliani <tahiliani@nitk.edu.in>
*
*/
#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<TcpNewReno> ()
.AddConstructor<TcpLp> ()
.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<TcpCongestionOps>
TcpLp::Fork (void)
{
return CopyObject<TcpLp> (this);
}
void
TcpLp::CongestionAvoidance (Ptr<TcpSocketState> 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<TcpSocketState> 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<TcpSocketState> 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<TcpSocketState> 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

122
src/internet/model/tcp-lp.h Normal file
View File

@@ -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 <charitha29193@gmail.com>
* Nandita G <gm.nandita@gmail.com>
* Mohit P. Tahiliani <tahiliani@nitk.edu.in>
*
*/
#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<TcpSocketState> tcb, uint32_t segmentsAcked,
const Time& rtt);
virtual std::string GetName () const;
virtual Ptr<TcpCongestionOps> 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<TcpSocketState> 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; //!<TcpLp state flag
uint32_t m_sOwd; //!<Smoothed One-Way Delay
uint32_t m_owdMin; //!<Minimum One-Way Delay
uint32_t m_owdMax; //!<Maximum One-Way Delay
uint32_t m_owdMaxRsv; //!<Reserved Maximum One-Way Delay
Time m_lastDrop; //!<Last time when cwnd was reduced
Time m_inference; //!<Current inference period
private:
/**
* \brief Calculates One-Way Delay using Sender and Receiver timestamps.
*
* \param tcb internal congestion state
* \return One-Way Delay
*/
uint32_t OwdCalculator (Ptr<TcpSocketState> tcb);
/**
* \brief Estimates minimum and maximum One-Way Delays and calculates the smoothed One-Way Delay.
*
* \param tcb internal congestion state
*/
void RttSample (Ptr<TcpSocketState> tcb);
};
} // namespace ns3
#endif // TCPLP_H

View File

@@ -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 <charitha29193@gmail.com>
* Nandita G <gm.nandita@gmail.com>
* Mohit P. Tahiliani <tahiliani@nitk.edu.in>
*
*/
#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<TcpSocketState> 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 <TcpSocketState> ();
m_state->m_cWnd = m_cWnd;
m_state->m_ssThresh = m_ssThresh;
m_state->m_segmentSize = m_segmentSize;
Ptr<TcpSocketState> state = CreateObject <TcpSocketState> ();
state->m_cWnd = m_cWnd;
state->m_ssThresh = m_ssThresh;
state->m_segmentSize = m_segmentSize;
Ptr<TcpLp> cong = CreateObject <TcpLp> ();
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<TcpNewReno> NewRenoCong = CreateObject <TcpNewReno> ();
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<TcpSocketState> 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 <TcpSocketState> ();
m_state->m_cWnd = m_cWnd;
m_state->m_segmentSize = m_segmentSize;
Ptr<TcpLp> cong = CreateObject <TcpLp> ();
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<TcpSocketState> 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 <TcpSocketState> ();
m_state->m_cWnd = m_cWnd;
m_state->m_segmentSize = m_segmentSize;
Ptr<TcpLp> cong = CreateObject <TcpLp> ();
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;
}

View File

@@ -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',