|
|
|
|
1 |
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ |
| 2 |
/* |
| 3 |
* Copyright (c) 2016 Natale Patriciello <natale.patriciello@gmail.com> |
| 4 |
* |
| 5 |
* This program is free software; you can redistribute it and/or modify |
| 6 |
* it under the terms of the GNU General Public License version 2 as |
| 7 |
* published by the Free Software Foundation; |
| 8 |
* |
| 9 |
* This program is distributed in the hope that it will be useful, |
| 10 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 11 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 12 |
* GNU General Public License for more details. |
| 13 |
* |
| 14 |
* You should have received a copy of the GNU General Public License |
| 15 |
* along with this program; if not, write to the Free Software |
| 16 |
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| 17 |
* |
| 18 |
*/ |
| 19 |
|
| 20 |
#include "tcp-general-test.h" |
| 21 |
#include "ns3/node.h" |
| 22 |
#include "ns3/log.h" |
| 23 |
#include "tcp-error-model.h" |
| 24 |
|
| 25 |
namespace ns3 { |
| 26 |
|
| 27 |
NS_LOG_COMPONENT_DEFINE ("TcpBytesInFlightTestSuite"); |
| 28 |
|
| 29 |
/** |
| 30 |
* \brief Check the value of BytesInFlight against a home-made guess |
| 31 |
* |
| 32 |
* The guess is made wrt to segments that travel the network; we have, |
| 33 |
* in theory, the possibility to know the real amount of bytes in flight. However |
| 34 |
* this value is useless, since the sender bases its guess on the received ACK. |
| 35 |
* |
| 36 |
* \see Tx |
| 37 |
* \see BytesInFlightTrace |
| 38 |
*/ |
| 39 |
class TcpBytesInFlightTest : public TcpGeneralTest |
| 40 |
{ |
| 41 |
public: |
| 42 |
TcpBytesInFlightTest (const std::string &desc, std::vector<uint32_t> &toDrop); |
| 43 |
|
| 44 |
protected: |
| 45 |
virtual Ptr<ErrorModel> CreateReceiverErrorModel (); |
| 46 |
virtual void Rx (const Ptr<const Packet> p, const TcpHeader&h, SocketWho who); |
| 47 |
virtual void Tx (const Ptr<const Packet> p, const TcpHeader&h, SocketWho who); |
| 48 |
virtual void BytesInFlightTrace (uint32_t oldValue, uint32_t newValue); |
| 49 |
|
| 50 |
void PktDropped (const Ipv4Header &ipH, const TcpHeader& tcpH, Ptr<const Packet> p); |
| 51 |
|
| 52 |
void FinalChecks (); |
| 53 |
|
| 54 |
private: |
| 55 |
uint32_t m_realBytesInFlight; |
| 56 |
uint32_t m_guessedBytesInFlight; |
| 57 |
uint32_t m_dupAckRecv; |
| 58 |
SequenceNumber32 m_lastAckRecv; |
| 59 |
SequenceNumber32 m_greatestSeqSent; |
| 60 |
std::vector<uint32_t> m_toDrop; // List of SequenceNumber to drop |
| 61 |
}; |
| 62 |
|
| 63 |
TcpBytesInFlightTest::TcpBytesInFlightTest (const std::string &desc, std::vector<uint32_t> &toDrop) |
| 64 |
: TcpGeneralTest (desc, 500, 30, Seconds (0.01), Seconds (0.05), Seconds (2.0), |
| 65 |
0xffffffff,1, 500), |
| 66 |
m_realBytesInFlight (0), |
| 67 |
m_guessedBytesInFlight (0), |
| 68 |
m_dupAckRecv (0), |
| 69 |
m_lastAckRecv (1), |
| 70 |
m_greatestSeqSent (0), |
| 71 |
m_toDrop (toDrop) |
| 72 |
{ |
| 73 |
} |
| 74 |
|
| 75 |
Ptr<ErrorModel> |
| 76 |
TcpBytesInFlightTest::CreateReceiverErrorModel () |
| 77 |
{ |
| 78 |
Ptr<TcpSeqErrorModel> m_errorModel = CreateObject<TcpSeqErrorModel> (); |
| 79 |
for (std::vector<uint32_t>::iterator it = m_toDrop.begin (); it != m_toDrop.end (); ++it) |
| 80 |
{ |
| 81 |
m_errorModel->AddSeqToKill (SequenceNumber32 (*it)); |
| 82 |
} |
| 83 |
|
| 84 |
m_errorModel->SetDropCallback (MakeCallback (&TcpBytesInFlightTest::PktDropped, this)); |
| 85 |
|
| 86 |
return m_errorModel; |
| 87 |
} |
| 88 |
|
| 89 |
void |
| 90 |
TcpBytesInFlightTest::PktDropped (const Ipv4Header &ipH, const TcpHeader &tcpH, |
| 91 |
Ptr<const Packet> p) |
| 92 |
{ |
| 93 |
NS_LOG_DEBUG ("Drop seq= " << tcpH.GetSequenceNumber () << " size " << p->GetSize ()); |
| 94 |
|
| 95 |
// These bytes leave the world, they were not loved by anyone |
| 96 |
m_realBytesInFlight -= p->GetSize (); |
| 97 |
} |
| 98 |
|
| 99 |
void |
| 100 |
TcpBytesInFlightTest::Rx (const Ptr<const Packet> p, const TcpHeader &h, SocketWho who) |
| 101 |
{ |
| 102 |
if (who == RECEIVER) |
| 103 |
{ |
| 104 |
// Received has got data; bytes are not in flight anymore |
| 105 |
m_realBytesInFlight -= p->GetSize (); |
| 106 |
} |
| 107 |
else if (who == SENDER) |
| 108 |
{ |
| 109 |
if (h.GetAckNumber () > m_lastAckRecv) |
| 110 |
{ // New ack |
| 111 |
uint32_t diff = h.GetAckNumber () - m_lastAckRecv; |
| 112 |
NS_LOG_DEBUG ("Recv ACK=" << h.GetAckNumber ()); |
| 113 |
|
| 114 |
if (m_dupAckRecv > 0) |
| 115 |
{ // Previously we got some ACKs |
| 116 |
if (h.GetAckNumber () >= m_greatestSeqSent) |
| 117 |
{ // This an ACK which acknowledge all the window |
| 118 |
diff -= (m_dupAckRecv * GetSegSize (SENDER)); |
| 119 |
|
| 120 |
if (diff > m_guessedBytesInFlight) |
| 121 |
{ |
| 122 |
// Our home-made guess is influenced also by retransmission |
| 123 |
// so make sure that this does not overflow |
| 124 |
diff = m_guessedBytesInFlight; |
| 125 |
} |
| 126 |
|
| 127 |
m_dupAckRecv = 0; |
| 128 |
} |
| 129 |
else |
| 130 |
{ |
| 131 |
// Partial ACK: Update the dupAck received count |
| 132 |
m_dupAckRecv -= diff / GetSegSize (SENDER); |
| 133 |
} |
| 134 |
} |
| 135 |
|
| 136 |
if ((h.GetFlags () & TcpHeader::FIN) != 0 |
| 137 |
|| m_guessedBytesInFlight + 1 == diff) |
| 138 |
{ // received the ACK for the FIN (which includes 1 spurious byte) |
| 139 |
diff -= 1; |
| 140 |
} |
| 141 |
m_guessedBytesInFlight -= diff; |
| 142 |
m_lastAckRecv = h.GetAckNumber (); |
| 143 |
NS_LOG_DEBUG ("Update m_guessedBytesInFlight to " << |
| 144 |
m_guessedBytesInFlight); |
| 145 |
} |
| 146 |
else if (h.GetAckNumber () == m_lastAckRecv |
| 147 |
&& m_lastAckRecv != SequenceNumber32 (1) |
| 148 |
&& (h.GetFlags () & TcpHeader::FIN) == 0) |
| 149 |
{ |
| 150 |
// For each dupack I should guess that a segment has been received |
| 151 |
// Please do not count FIN and SYN/ACK as dupacks |
| 152 |
m_guessedBytesInFlight -= GetSegSize (SENDER); |
| 153 |
m_dupAckRecv++; |
| 154 |
NS_LOG_DEBUG ("Dupack received, Update m_guessedBytesInFlight to " << |
| 155 |
m_guessedBytesInFlight); |
| 156 |
} |
| 157 |
|
| 158 |
} |
| 159 |
} |
| 160 |
|
| 161 |
void |
| 162 |
TcpBytesInFlightTest::Tx (const Ptr<const Packet> p, const TcpHeader &h, SocketWho who) |
| 163 |
{ |
| 164 |
if (who == SENDER) |
| 165 |
{ |
| 166 |
m_realBytesInFlight += p->GetSize (); |
| 167 |
if (m_greatestSeqSent <= h.GetSequenceNumber ()) |
| 168 |
{ // This is not a retransmission |
| 169 |
m_guessedBytesInFlight += p->GetSize (); |
| 170 |
m_greatestSeqSent = h.GetSequenceNumber (); |
| 171 |
} |
| 172 |
|
| 173 |
// TODO: Maybe we need to account retransmission in another variable, |
| 174 |
// such as m_guessedRetransOut ? |
| 175 |
|
| 176 |
NS_LOG_DEBUG ("TX size=" << p->GetSize () << " seq=" << h.GetSequenceNumber () << |
| 177 |
" m_guessedBytesInFlight=" << m_guessedBytesInFlight); |
| 178 |
} |
| 179 |
} |
| 180 |
|
| 181 |
void |
| 182 |
TcpBytesInFlightTest::BytesInFlightTrace (uint32_t oldValue, uint32_t newValue) |
| 183 |
{ |
| 184 |
NS_LOG_DEBUG ("Socket BytesInFlight=" << newValue << |
| 185 |
" mine is=" << m_guessedBytesInFlight); |
| 186 |
NS_TEST_ASSERT_MSG_EQ (m_guessedBytesInFlight, newValue, |
| 187 |
"Guessed and measured bytes in flight differs"); |
| 188 |
} |
| 189 |
|
| 190 |
void |
| 191 |
TcpBytesInFlightTest::FinalChecks () |
| 192 |
{ |
| 193 |
NS_TEST_ASSERT_MSG_EQ (m_guessedBytesInFlight, 0, |
| 194 |
"Still present bytes in flight at the end of the transmission"); |
| 195 |
} |
| 196 |
|
| 197 |
//----------------------------------------------------------------------------- |
| 198 |
|
| 199 |
static class TcpBytesInFlightTestSuite : public TestSuite |
| 200 |
{ |
| 201 |
public: |
| 202 |
TcpBytesInFlightTestSuite () : TestSuite ("tcp-bytes-in-flight-test", UNIT) |
| 203 |
{ |
| 204 |
std::vector<uint32_t> toDrop; |
| 205 |
AddTestCase (new TcpBytesInFlightTest ("BytesInFlight value, no drop", toDrop), |
| 206 |
TestCase::QUICK); |
| 207 |
toDrop.push_back (4001); |
| 208 |
AddTestCase (new TcpBytesInFlightTest ("BytesInFlight value, one drop", toDrop), |
| 209 |
TestCase::QUICK); |
| 210 |
toDrop.push_back (4001); |
| 211 |
AddTestCase (new TcpBytesInFlightTest ("BytesInFlight value, two drop of same segment", toDrop), |
| 212 |
TestCase::QUICK); |
| 213 |
toDrop.pop_back (); |
| 214 |
toDrop.push_back (4501); |
| 215 |
AddTestCase (new TcpBytesInFlightTest ("BytesInFlight value, two drop of consecutive segments", toDrop), |
| 216 |
TestCase::QUICK); |
| 217 |
} |
| 218 |
} g_tcpBytesInFlightTestSuite; |
| 219 |
|
| 220 |
} // namespace ns3 |