View | Details | Raw Unified | Return to bug 2559
Collapse All | Expand All

(-)a/src/internet/model/tcp-socket-base.cc (-1 / +2 lines)
 Lines 2749-2755   uint16_t Link Here 
2749
TcpSocketBase::AdvertisedWindowSize (bool scale) const
2749
TcpSocketBase::AdvertisedWindowSize (bool scale) const
2750
{
2750
{
2751
  NS_LOG_FUNCTION (this << scale);
2751
  NS_LOG_FUNCTION (this << scale);
2752
  uint32_t w = m_rxBuffer->MaxBufferSize ();
2752
  uint32_t w = (m_rxBuffer->MaxRxSequence () > m_rxBuffer->NextRxSequence ()) ?
2753
                m_rxBuffer->MaxRxSequence () - m_rxBuffer->NextRxSequence () : 0;
2753
2754
2754
  if (scale)
2755
  if (scale)
2755
    {
2756
    {
(-)a/src/internet/test/tcp-advertised-window-test.cc (+325 lines)
Line 0    Link Here 
1
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2
/*
3
 * Copyright (c) 2017 Christoph Doepmann <doepmanc@informatik.hu-berlin.de>
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
#include "ns3/random-variable-stream.h"
25
26
namespace ns3 {
27
28
NS_LOG_COMPONENT_DEFINE ("TcpAdvertisedWindowTestSuite");
29
30
/**
31
 * \brief Socket that wraps every call to AdvertisedWindowSize ().
32
 */
33
34
class TcpSocketAdvertisedWindowProxy : public TcpSocketMsgBase
35
{
36
public:
37
  static TypeId GetTypeId (void);
38
39
  typedef Callback<void, uint16_t, uint16_t> InvalidAwndCallback;
40
41
  TcpSocketAdvertisedWindowProxy () : TcpSocketMsgBase (), m_segmentSize(0)
42
  {
43
  }
44
45
  TcpSocketAdvertisedWindowProxy (const TcpSocketAdvertisedWindowProxy &other)
46
    : TcpSocketMsgBase (other)
47
  {
48
    m_segmentSize = other.m_segmentSize;
49
    m_inwalidAwndCb = other.m_inwalidAwndCb;
50
  }
51
52
  void SetInvalidAwndCb (InvalidAwndCallback cb);
53
54
  void SetExpectedSegmentSize (uint16_t seg) { m_segmentSize = seg; };
55
56
protected:
57
  virtual Ptr<TcpSocketBase> Fork ();
58
  virtual uint16_t AdvertisedWindowSize (bool scale = true) const;
59
60
private:
61
  uint16_t OldAdvertisedWindowSize (bool scale = true) const;
62
  InvalidAwndCallback m_inwalidAwndCb;
63
64
  /**
65
   * \brief Test meta-information: size of the segments that are received.
66
   * 
67
   * This is necessary for making sure the calculated awnd only differs by
68
   * exactly that one segment that was not yet read by the application.
69
   */
70
  uint16_t m_segmentSize;
71
};
72
73
void
74
TcpSocketAdvertisedWindowProxy::SetInvalidAwndCb (InvalidAwndCallback cb)
75
{
76
  NS_ASSERT (!cb.IsNull ());
77
  m_inwalidAwndCb = cb;
78
}
79
80
TypeId
81
TcpSocketAdvertisedWindowProxy::GetTypeId (void)
82
{
83
  static TypeId tid = TypeId ("ns3::TcpSocketAdvertisedWindowProxy")
84
    .SetParent<TcpSocketMsgBase> ()
85
    .SetGroupName ("Internet")
86
    .AddConstructor<TcpSocketAdvertisedWindowProxy> ()
87
  ;
88
  return tid;
89
}
90
91
Ptr<TcpSocketBase>
92
TcpSocketAdvertisedWindowProxy::Fork (void)
93
{
94
  return CopyObject<TcpSocketAdvertisedWindowProxy> (this);
95
}
96
97
uint16_t
98
TcpSocketAdvertisedWindowProxy::AdvertisedWindowSize (bool scale) const
99
{
100
  NS_LOG_FUNCTION (this << scale);
101
102
  uint16_t newAwnd = TcpSocketMsgBase::AdvertisedWindowSize (scale);
103
  uint16_t oldAwnd = OldAdvertisedWindowSize (scale);
104
105
  if (!m_rxBuffer->Finished ())
106
    {
107
      // The calculated windows will only be exactly equal if there is no data
108
      // in the receive buffer yet.
109
      if (newAwnd != oldAwnd)
110
        {
111
          uint32_t available = m_rxBuffer->Available ();
112
          // If the values differ, make sure this is only due to the single segment
113
          // the socket just got, which has not yet been read by the application.
114
          // Therefore, the difference should be exactly the size of one segment
115
          // (but taking scale and m_maxWinSize into account).
116
          uint32_t newAwndKnownDifference = newAwnd;
117
          if (scale)
118
            {
119
              newAwndKnownDifference += (available >> m_rcvWindShift);
120
            }
121
          else
122
            {
123
              newAwndKnownDifference += available;
124
            }
125
126
          if (newAwndKnownDifference > m_maxWinSize)
127
            {
128
              newAwndKnownDifference = m_maxWinSize;
129
            }
130
131
          if (static_cast<uint16_t> (newAwndKnownDifference) != oldAwnd)
132
            {
133
              if (!m_inwalidAwndCb.IsNull ())
134
                {
135
                  m_inwalidAwndCb(oldAwnd, newAwnd);
136
                }
137
138
            }
139
        }
140
    }
141
142
143
  return newAwnd;
144
}
145
146
/**
147
 * The legacy code used for calculating the advertised window.
148
 *
149
 * This was copied from tcp-socket-base.cc before changing the formula.
150
 */
151
uint16_t
152
TcpSocketAdvertisedWindowProxy::OldAdvertisedWindowSize (bool scale) const
153
{
154
  NS_LOG_FUNCTION (this << scale);
155
  //NS_LOG_DEBUG ("MaxRxSequence () = " << m_rxBuffer->MaxRxSequence ());
156
  //NS_LOG_DEBUG ("NextRxSequence () = " << m_rxBuffer->NextRxSequence ());
157
  //NS_LOG_DEBUG ("MaxBufferSize () = " << m_rxBuffer->MaxBufferSize ());
158
  //NS_LOG_DEBUG ("m_rcvWindShift = " << static_cast<uint16_t> (m_rcvWindShift));
159
  //NS_LOG_DEBUG ("m_maxWinSize = " << m_maxWinSize);
160
  //NS_LOG_DEBUG ("Available () = " << m_rxBuffer->Available ());
161
  uint32_t w = m_rxBuffer->MaxBufferSize ();
162
163
  if (scale)
164
    {
165
      w >>= m_rcvWindShift;
166
    }
167
  if (w > m_maxWinSize)
168
    {
169
      w = m_maxWinSize;
170
      NS_LOG_WARN ("Adv window size truncated to " << m_maxWinSize << "; possibly to avoid overflow of the 16-bit integer");
171
    }
172
  NS_LOG_DEBUG ("Returning AdvertisedWindowSize of " << static_cast<uint16_t> (w));
173
  return static_cast<uint16_t> (w);
174
}
175
176
NS_OBJECT_ENSURE_REGISTERED (TcpSocketAdvertisedWindowProxy);
177
178
/**
179
 * \brief An error model that randomly drops a given rĂ¡tio of TCP segments.
180
 */
181
class TcpDropRatioErrorModel : public TcpGeneralErrorModel
182
{
183
public:
184
  static TypeId GetTypeId (void);
185
  TcpDropRatioErrorModel (double dropRatio)
186
    : TcpGeneralErrorModel (), m_dropRatio(dropRatio)
187
  {
188
    m_prng = CreateObject<UniformRandomVariable> ();
189
  }
190
191
protected:
192
  virtual bool ShouldDrop (const Ipv4Header &ipHeader, const TcpHeader &tcpHeader,
193
                           uint32_t packetSize);
194
195
private:
196
  virtual void DoReset (void) { };
197
  double m_dropRatio;
198
  Ptr<UniformRandomVariable> m_prng;
199
};
200
201
NS_OBJECT_ENSURE_REGISTERED (TcpDropRatioErrorModel);
202
203
TypeId
204
TcpDropRatioErrorModel::GetTypeId (void)
205
{
206
  static TypeId tid = TypeId ("ns3::TcpDropRatioErrorModel")
207
    .SetParent<TcpGeneralErrorModel> ()
208
  ;
209
  return tid;
210
}
211
212
bool
213
TcpDropRatioErrorModel::ShouldDrop (const Ipv4Header &ipHeader, const TcpHeader &tcpHeader,
214
                              uint32_t packetSize)
215
{
216
  return m_prng->GetValue () < m_dropRatio; 
217
}
218
219
/**
220
 * \brief Test the new formula for calculating TCP's advertised window size.
221
 *
222
 * In TcpSocketBase, the advertised window is now calculated as
223
 *
224
 *   m_rxBuffer->MaxRxSequence () - m_rxBuffer->NextRxSequence ()
225
 * 
226
 * instead ofthe previous
227
 *
228
 *   m_rxBuffer->MaxBufferSize ()
229
 * 
230
 * This change was introduced with regard to situations in which the receiviing
231
 * application does not read from the socket as fast as possible (see bug 2559
232
 * for details). This test ensures that no regression is introduced for other,
233
 * "normal" cases.
234
 *
235
 * TcpGeneralTest ensures via ReceivePacket () that incoming packets are
236
 * quickly consumed by the application layer, simulating a fast-reading
237
 * application. We can only reasonably compare the old and the new AWND
238
 * computation in this case.
239
 */
240
class TcpAdvertisedWindowTest : public TcpGeneralTest
241
{
242
public:
243
  TcpAdvertisedWindowTest (const std::string &desc, uint32_t size, uint32_t packets, double lossRatio);
244
245
protected:
246
  virtual void ConfigureEnvironment ();
247
  virtual Ptr<TcpSocketMsgBase> CreateReceiverSocket (Ptr<Node> node);
248
  virtual Ptr<ErrorModel> CreateReceiverErrorModel ();
249
250
private:
251
  void InvalidAwndCb (uint16_t oldAwnd, uint16_t newAwnd);
252
  uint32_t m_pktSize;
253
  uint32_t m_pktCount;
254
  double m_lossRatio;
255
};
256
257
TcpAdvertisedWindowTest::TcpAdvertisedWindowTest (const std::string &desc,
258
                                              uint32_t size, uint32_t packets, double lossRatio)
259
  : TcpGeneralTest (desc),
260
    m_pktSize (size),
261
    m_pktCount (packets),
262
    m_lossRatio (lossRatio)
263
{
264
}
265
266
void
267
TcpAdvertisedWindowTest::ConfigureEnvironment ()
268
{
269
  TcpGeneralTest::ConfigureEnvironment ();
270
  SetAppPktCount (m_pktCount);
271
  SetPropagationDelay (MilliSeconds (50));
272
  SetTransmitStart (Seconds (2.0));
273
  SetAppPktSize (m_pktSize);
274
275
}
276
277
Ptr<TcpSocketMsgBase>
278
TcpAdvertisedWindowTest::CreateReceiverSocket (Ptr<Node> node)
279
{
280
  NS_LOG_FUNCTION (this);
281
282
  Ptr<TcpSocketMsgBase> sock = CreateSocket (node, TcpSocketAdvertisedWindowProxy::GetTypeId (), m_congControlTypeId);
283
  DynamicCast<TcpSocketAdvertisedWindowProxy> (sock)->SetExpectedSegmentSize (500);
284
  DynamicCast<TcpSocketAdvertisedWindowProxy> (sock)->SetInvalidAwndCb (
285
        MakeCallback (&TcpAdvertisedWindowTest::InvalidAwndCb, this));
286
287
  return sock;
288
}
289
290
Ptr<ErrorModel>
291
TcpAdvertisedWindowTest::CreateReceiverErrorModel ()
292
{
293
  return CreateObject<TcpDropRatioErrorModel> (m_lossRatio);
294
}
295
296
void
297
TcpAdvertisedWindowTest::InvalidAwndCb (uint16_t oldAwnd, uint16_t newAwnd)
298
{
299
  NS_TEST_ASSERT_MSG_EQ (oldAwnd, newAwnd,
300
                         "Old and new AWND calculations do not match.");
301
}
302
303
//-----------------------------------------------------------------------------
304
305
static class TcpAdvertisedWindowTestSuite : public TestSuite
306
{
307
public:
308
  TcpAdvertisedWindowTestSuite () : TestSuite ("tcp-advertised-window-test", UNIT)
309
  {
310
    AddTestCase (new TcpAdvertisedWindowTest ("TCP advertised window size, small seg + no loss", 500, 100, 0.0),
311
                 TestCase::QUICK);
312
    AddTestCase (new TcpAdvertisedWindowTest ("TCP advertised window size, small seg + loss", 500, 100, 0.1),
313
                 TestCase::QUICK);
314
    AddTestCase (new TcpAdvertisedWindowTest ("TCP advertised window size, large seg + no loss", 1000, 100, 0.0),
315
                 TestCase::QUICK);
316
    AddTestCase (new TcpAdvertisedWindowTest ("TCP advertised window size, large seg + small loss", 1000, 100, 0.1),
317
                 TestCase::QUICK);
318
    AddTestCase (new TcpAdvertisedWindowTest ("TCP advertised window size, large seg + big loss", 1000, 100, 0.3),
319
                 TestCase::QUICK);
320
    AddTestCase (new TcpAdvertisedWindowTest ("TCP advertised window size, complete loss", 1000, 100, 1.0),
321
                 TestCase::QUICK);
322
  }
323
} g_tcpAdvertisedWindowTestSuite;
324
325
} // namespace ns3
(-)a/src/internet/wscript (+1 lines)
 Lines 265-270   def build(bld): Link Here 
265
        'test/tcp-pkts-acked-test.cc',
265
        'test/tcp-pkts-acked-test.cc',
266
        'test/tcp-rtt-estimation.cc',
266
        'test/tcp-rtt-estimation.cc',
267
        'test/tcp-bytes-in-flight-test.cc',
267
        'test/tcp-bytes-in-flight-test.cc',
268
        'test/tcp-advertised-window-test.cc',
268
        'test/udp-test.cc',
269
        'test/udp-test.cc',
269
        'test/ipv6-address-generator-test-suite.cc',
270
        'test/ipv6-address-generator-test-suite.cc',
270
        'test/ipv6-dual-stack-test-suite.cc',
271
        'test/ipv6-dual-stack-test-suite.cc',

Return to bug 2559