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

(-)a/src/internet/test/tcp-bytes-in-flight-test.cc (+220 lines)
Line 0    Link Here 
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
(-)a/src/internet/wscript (+1 lines)
 Lines 243-248   def build(bld): Link Here 
243
        'test/tcp-hybla-test.cc',
243
        'test/tcp-hybla-test.cc',
244
        'test/tcp-zero-window-test.cc',
244
        'test/tcp-zero-window-test.cc',
245
        'test/tcp-pkts-acked-test.cc',
245
        'test/tcp-pkts-acked-test.cc',
246
        'test/tcp-bytes-in-flight-test.cc',
246
        'test/udp-test.cc',
247
        'test/udp-test.cc',
247
        'test/ipv6-address-generator-test-suite.cc',
248
        'test/ipv6-address-generator-test-suite.cc',
248
        'test/ipv6-dual-stack-test-suite.cc',
249
        'test/ipv6-dual-stack-test-suite.cc',

Return to bug 1783