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