A Discrete-Event Network Simulator
API
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
ns3tcp-state-test-suite.cc
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2010 University of Washington
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 #include <iomanip>
20 #include <string>
21 
22 #include "ns3/log.h"
23 #include "ns3/abort.h"
24 #include "ns3/test.h"
25 #include "ns3/pcap-file.h"
26 #include "ns3/config.h"
27 #include "ns3/string.h"
28 #include "ns3/uinteger.h"
29 #include "ns3/data-rate.h"
30 #include "ns3/inet-socket-address.h"
31 #include "ns3/point-to-point-helper.h"
32 #include "ns3/internet-stack-helper.h"
33 #include "ns3/ipv4-global-routing-helper.h"
34 #include "ns3/ipv4-address-helper.h"
35 #include "ns3/packet-sink-helper.h"
36 #include "ns3/tcp-socket-factory.h"
37 #include "ns3/node-container.h"
38 #include "ns3/simulator.h"
39 #include "ns3/error-model.h"
40 #include "ns3/pointer.h"
41 #include "ns3tcp-socket-writer.h"
42 
43 using namespace ns3;
44 
45 NS_LOG_COMPONENT_DEFINE ("Ns3TcpStateTest");
46 
47 const bool WRITE_VECTORS = false; // set to true to write response vectors
48 const bool WRITE_LOGGING = false; // set to true to write logging
49 const uint32_t PCAP_LINK_TYPE = 1187373554; // Some large random number -- we use to verify data was written by this program
50 const uint32_t PCAP_SNAPLEN = 64; // Don't bother to save much data
51 
52 // ===========================================================================
53 // Tests of TCP implementation loss behavior
54 // ===========================================================================
55 //
56 
58 {
59 public:
61  Ns3TcpStateTestCase (uint32_t testCase);
62  virtual ~Ns3TcpStateTestCase () {}
63 
64 private:
65  virtual void DoSetup (void);
66  virtual void DoRun (void);
67  virtual void DoTeardown (void);
68 
69  std::string m_pcapFilename;
71  uint32_t m_testCase;
72  uint32_t m_totalTxBytes;
73  uint32_t m_currentTxBytes;
78 
79  void Ipv4L3Tx (std::string context, Ptr<const Packet> packet, Ptr<Ipv4> ipv4, uint32_t interface);
80  void WriteUntilBufferFull (Ptr<Socket> localSocket, uint32_t txSpace);
81  void StartFlow (Ptr<Socket> localSocket,
82  Ipv4Address servAddress,
83  uint16_t servPort);
84 
85 };
86 
88  : TestCase ("Check the operation of the TCP state machine for several cases"),
89  m_testCase (0),
90  m_totalTxBytes (20000),
91  m_currentTxBytes (0),
92  m_writeVectors (WRITE_VECTORS),
93  m_writeResults (false),
94  m_writeLogging (WRITE_LOGGING),
95  m_needToClose (true)
96 {
97 }
98 
100  : TestCase ("Check the operation of the TCP state machine for several cases"),
101  m_testCase (testCase),
102  m_totalTxBytes (20000),
103  m_currentTxBytes (0),
104  m_writeVectors (WRITE_VECTORS),
105  m_writeResults (false),
106  m_writeLogging (WRITE_LOGGING),
107  m_needToClose (true)
108 {
109 }
110 
111 void
113 {
114  //
115  // We expect there to be a file called ns3tcp-state-response-vectors.pcap in
116  // response-vectors/ of this directory
117  //
118  std::ostringstream oss;
119  oss << "/response-vectors/ns3tcp-state" << m_testCase << "-response-vectors.pcap";
120  m_pcapFilename = static_cast<std::string> (NS_TEST_SOURCEDIR) + oss.str ();
121 
122  if (m_writeVectors)
123  {
124  m_pcapFile.Open (m_pcapFilename, std::ios::out|std::ios::binary);
126  }
127  else
128  {
129  m_pcapFile.Open (m_pcapFilename, std::ios::in|std::ios::binary);
130  NS_ABORT_MSG_UNLESS (m_pcapFile.GetDataLinkType () == PCAP_LINK_TYPE, "Wrong response vectors in directory");
131  }
132 }
133 
134 void
136 {
137  m_pcapFile.Close ();
138 }
139 
140 void
141 Ns3TcpStateTestCase::Ipv4L3Tx (std::string context, Ptr<const Packet> packet, Ptr<Ipv4> ipv4, uint32_t interface)
142 {
143  //
144  // We're not testing IP so remove and toss the header. In order to do this,
145  // though, we need to copy the packet since we have a const version.
146  //
147  Ptr<Packet> p = packet->Copy ();
148  Ipv4Header ipHeader;
149  p->RemoveHeader (ipHeader);
150 
151  //
152  // What is left is the TCP header and any data that may be sent. We aren't
153  // sending any TCP data, so we expect what remains is only TCP header, which
154  // is a small thing to save.
155  //
156  if (m_writeVectors)
157  {
158  //
159  // Save the TCP under test response for later testing.
160  //
161  Time tNow = Simulator::Now ();
162  int64_t tMicroSeconds = tNow.GetMicroSeconds ();
163 
164  uint32_t size = p->GetSize ();
165  uint8_t *buf = new uint8_t[size];
166  p->CopyData (buf, size);
167 
168  m_pcapFile.Write (uint32_t (tMicroSeconds / 1000000),
169  uint32_t (tMicroSeconds % 1000000),
170  buf,
171  size);
172  delete [] buf;
173  }
174  else
175  {
176  //
177  // Read the TCP under test expected response from the expected vector
178  // file and see if it still does the right thing.
179  //
180  uint8_t expected[PCAP_SNAPLEN];
181  uint32_t tsSec, tsUsec, inclLen, origLen, readLen;
182  m_pcapFile.Read (expected, sizeof(expected), tsSec, tsUsec, inclLen, origLen, readLen);
183 
184  uint8_t *actual = new uint8_t[readLen];
185  p->CopyData (actual, readLen);
186 
187  uint32_t result = memcmp (actual, expected, readLen);
188 
189  delete [] actual;
190 
191  //
192  // Avoid streams of errors -- only report the first.
193  //
194  if (IsStatusSuccess ())
195  {
196  NS_TEST_EXPECT_MSG_EQ (result, 0, "Expected data comparison error");
197  }
198  }
199 }
200 
202 // Implementing an "application" to send bytes over a TCP connection
203 void
205 {
207  {
208  uint32_t left = m_totalTxBytes - m_currentTxBytes;
209  uint32_t dataOffset = m_currentTxBytes % 1040;
210  uint32_t toWrite = 1040 - dataOffset;
211  uint32_t txAvail = localSocket->GetTxAvailable ();
212  toWrite = std::min (toWrite, left);
213  toWrite = std::min (toWrite, txAvail);
214  if (txAvail == 0)
215  {
216  return;
217  };
218  if (m_writeLogging)
219  {
220  std::clog << "Submitting "
221  << toWrite << " bytes to TCP socket" << std::endl;
222  }
223  int amountSent = localSocket->Send (0, toWrite, 0);
224  NS_ASSERT (amountSent > 0); // Given GetTxAvailable() non-zero, amountSent should not be zero
225  m_currentTxBytes += amountSent;
226  }
227  if (m_needToClose)
228  {
229  if (m_writeLogging)
230  {
231  std::clog << "Close socket at "
232  << Simulator::Now ().GetSeconds ()
233  << std::endl;
234  }
235  localSocket->Close ();
236  m_needToClose = false;
237  }
238 }
239 
240 void
242  Ipv4Address servAddress,
243  uint16_t servPort)
244 {
245  if (m_writeLogging)
246  {
247  std::clog << "Starting flow at time "
248  << Simulator::Now ().GetSeconds ()
249  << std::endl;
250  }
251 
252  localSocket->Connect (InetSocketAddress (servAddress, servPort)); // connect
253 
254  // tell the tcp implementation to call WriteUntilBufferFull again
255  // if we blocked and new tx buffer space becomes available
256  localSocket->SetSendCallback (MakeCallback
258  this));
259  WriteUntilBufferFull (localSocket, localSocket->GetTxAvailable ());
260 }
261 
262 void
264 {
265  // Network topology
266  //
267  // 10Mb/s, 0.1ms 10Mb/s, 0.1ms
268  // n0-----------------n1-----------------n2
269 
270  std::string tcpModel ("ns3::TcpNewReno");
271 
272  Config::SetDefault ("ns3::TcpL4Protocol::SocketType", StringValue (tcpModel));
273  Config::SetDefault ("ns3::TcpSocket::SegmentSize", UintegerValue (1000));
274  Config::SetDefault ("ns3::TcpSocket::DelAckCount", UintegerValue (1));
275  Config::SetDefault ("ns3::DropTailQueue::MaxPackets", UintegerValue (20));
276 
277  if (m_writeLogging)
278  {
280  LogComponentEnable ("TcpTestCases", LOG_LEVEL_ALL);
281  LogComponentEnable ("ErrorModel", LOG_LEVEL_DEBUG);
282  LogComponentEnable ("TcpTestCases", LOG_LEVEL_ALL);
283  LogComponentEnable ("TcpNewReno", LOG_LEVEL_INFO);
284  LogComponentEnable ("TcpReno", LOG_LEVEL_INFO);
285  LogComponentEnable ("TcpTahoe", LOG_LEVEL_INFO);
286  LogComponentEnable ("TcpSocketBase", LOG_LEVEL_INFO);
287  }
288 
290  // Topology construction
291  //
292 
293  // Create three nodes
294  NodeContainer n0n1;
295  n0n1.Create (2);
296 
298  n1n2.Add (n0n1.Get (1));
299  n1n2.Create (1);
300 
301  // Set up TCP/IP stack to all nodes (and create loopback device at device 0)
302  InternetStackHelper internet;
303  internet.InstallAll ();
304 
305  // Connect the nodes
306  PointToPointHelper p2p;
307  p2p.SetDeviceAttribute ("DataRate", DataRateValue (DataRate (1000000)));
308  p2p.SetChannelAttribute ("Delay", TimeValue (Seconds (0.0001)));
309  NetDeviceContainer dev0 = p2p.Install (n0n1);
310  NetDeviceContainer dev1 = p2p.Install (n1n2);
311 
312  // Add IP addresses to each network interfaces
313  Ipv4AddressHelper ipv4;
314  ipv4.SetBase ("10.1.3.0", "255.255.255.0");
315  ipv4.Assign (dev0);
316  ipv4.SetBase ("10.1.2.0", "255.255.255.0");
317  Ipv4InterfaceContainer ipInterfs = ipv4.Assign (dev1);
318 
319  // Set up routes to all nodes
320  Ipv4GlobalRoutingHelper::PopulateRoutingTables ();
321 
323  // A flow from node n0 to node n2
324  //
325 
326  // Create a packet sink to receive packets on node n2
327  uint16_t servPort = 50000; // Destination port number
328  PacketSinkHelper sink ("ns3::TcpSocketFactory", InetSocketAddress (Ipv4Address::GetAny (), servPort));
329  ApplicationContainer sinkApps = sink.Install (n1n2.Get (1));
330  sinkApps.Start (Seconds (0.0));
331  sinkApps.Stop (Seconds (100.0));
332 
333  // Create a data source to send packets on node n0
334  // Instead of full application, here use the socket directly by
335  // registering callbacks in function StarFlow().
336  Ptr<Socket> localSocket = Socket::CreateSocket (n0n1.Get (0),
337  TcpSocketFactory::GetTypeId ());
338  localSocket->Bind ();
339  Simulator::ScheduleNow (&Ns3TcpStateTestCase::StartFlow, this,
340  localSocket, ipInterfs.GetAddress (1), servPort);
341 
342  Config::Connect ("/NodeList/0/$ns3::Ipv4L3Protocol/Tx",
344 
346  // Set up different test cases: Lost model at node n1, different file size
347  //
348 
349  std::list<uint32_t> dropListN0;
350  std::list<uint32_t> dropListN1;
351  std::string caseDescription;
352  switch (m_testCase)
353  {
354  case 0:
355  m_totalTxBytes = 1000;
356  caseDescription = "Verify connection establishment";
357  break;
358  case 1:
359  m_totalTxBytes = 100*1000;
360  caseDescription = "Verify a bigger (100 pkts) transfer: Sliding window operation, etc.";
361  break;
362  case 2:
363  m_totalTxBytes = 1000;
364  caseDescription = "Survive a SYN lost";
365  dropListN0.push_back (0);
366  break;
367  case 3:
368  m_totalTxBytes = 2000;
369  caseDescription = "Survive a SYN+ACK lost";
370  dropListN1.push_back (0);
371  break;
372  case 4:
373  m_totalTxBytes = 2000;
374  caseDescription = "Survive a ACK (last packet in 3-way handshake) lost";
375  dropListN0.push_back (1);
376  break;
377  case 5:
378  m_totalTxBytes = 0;
379  caseDescription = "Immediate FIN upon SYN_RCVD";
380  m_needToClose = false;
381  dropListN0.push_back (1); // Hide the ACK in 3WHS
382  Simulator::Schedule (Seconds (0.002), &Socket::Close, localSocket);
383  break;
384  case 6:
385  m_totalTxBytes = 5000;
386  caseDescription = "Simulated simultaneous close";
387  dropListN1.push_back (5); // Hide the ACK-to-FIN from n2
388  break;
389  case 7:
390  m_totalTxBytes = 5000;
391  caseDescription = "FIN check 1: Loss of initiator's FIN. Wait until app close";
392  m_needToClose = false;
393  dropListN0.push_back (7); // Hide the FIN from n0
394  Simulator::Schedule (Seconds (0.04), &Socket::Close, localSocket);
395  break;
396  case 8:
397  m_totalTxBytes = 5000;
398  caseDescription = "FIN check 2: Loss responder's FIN. FIN will be resent after last ack timeout";
399  dropListN1.push_back (6); // Hide the FIN from n2
400  break;
401  default:
402  NS_FATAL_ERROR ("Program fatal error: specified test case not supported: "
403  << m_testCase);
404  break;
405  }
406 
407  Ptr<ReceiveListErrorModel> errN0 = CreateObject<ReceiveListErrorModel> ();
408  errN0->SetList (dropListN0);
409  dev0.Get (1)->SetAttribute ("ReceiveErrorModel", PointerValue (errN0));
410 
411  Ptr<ReceiveListErrorModel> errN1 = CreateObject<ReceiveListErrorModel> ();
412  errN1->SetList (dropListN1);
413  dev1.Get (0)->SetAttribute ("ReceiveErrorModel", PointerValue (errN1));
414 
415  std::ostringstream oss;
416  oss << "tcp-state" << m_testCase << "-test-case";
417  if (m_writeResults)
418  {
419  p2p.EnablePcapAll (oss.str ());
420  p2p.EnableAsciiAll (oss.str ());
421  }
422 
423  if (m_writeLogging)
424  {
425  Ptr<OutputStreamWrapper> osw = Create<OutputStreamWrapper> (&std::clog);
426  *(osw->GetStream ()) << std::setprecision (9) << std::fixed;
427  p2p.EnableAsciiAll (osw);
428 
429  std::clog << std::endl << "Running TCP test-case " << m_testCase << ": "
430  << caseDescription << std::endl;
431  }
432 
433  // Finally, set up the simulator to run. The 1000 second hard limit is a
434  // failsafe in case some change above causes the simulation to never end
435  Simulator::Stop (Seconds (1000));
436  Simulator::Run ();
437  Simulator::Destroy ();
438 
439 
440 }
441 
443 {
444 public:
446 };
447 
449  : TestSuite ("ns3-tcp-state", SYSTEM)
450 {
451  Packet::EnablePrinting (); // Enable packet metadata for all test cases
452  AddTestCase (new Ns3TcpStateTestCase (0), TestCase::QUICK);
453  AddTestCase (new Ns3TcpStateTestCase (1), TestCase::QUICK);
454  AddTestCase (new Ns3TcpStateTestCase (2), TestCase::QUICK);
455  AddTestCase (new Ns3TcpStateTestCase (3), TestCase::QUICK);
456  AddTestCase (new Ns3TcpStateTestCase (4), TestCase::QUICK);
457  AddTestCase (new Ns3TcpStateTestCase (5), TestCase::QUICK);
458  AddTestCase (new Ns3TcpStateTestCase (6), TestCase::QUICK);
459  AddTestCase (new Ns3TcpStateTestCase (7), TestCase::QUICK);
460  AddTestCase (new Ns3TcpStateTestCase (8), TestCase::QUICK);
461 }
462 
uint32_t RemoveHeader(Header &header)
Deserialize and remove the header from the internal buffer.
Definition: packet.cc:268
holds a vector of ns3::Application pointers.
void LogComponentEnableAll(enum LogLevel level)
Definition: log.cc:335
keep track of time values and allow control of global simulation resolution
Definition: nstime.h:81
an Inet address class
NodeContainer n1n2
Definition: red-tests.cc:63
NS_LOG_COMPONENT_DEFINE("GrantedTimeWindowMpiInterface")
holds a vector of std::pair of Ptr and interface index.
hold variables of type string
Definition: string.h:19
Ptr< NetDevice > Get(uint32_t i) const
Get the Ptr stored in this container at a given index.
NetDeviceContainer Install(NodeContainer c)
A suite of tests to run.
Definition: test.h:1025
#define NS_ASSERT(condition)
Definition: assert.h:64
aggregate IP/TCP/UDP functionality to existing Nodes.
uint32_t GetSize(void) const
Definition: packet.h:650
A helper to make it easier to instantiate an ns3::PacketSinkApplication on a set of nodes...
Build a set of PointToPointNetDevice objects.
encapsulates test code
Definition: test.h:849
void Connect(std::string path, const CallbackBase &cb)
Definition: config.cc:728
void StartFlow(Ptr< Socket > localSocket, Ipv4Address servAddress, uint16_t servPort)
void SetDeviceAttribute(std::string name, const AttributeValue &value)
Set an attribute value to be propagated to each NetDevice created by the helper.
#define NS_ABORT_MSG_UNLESS(cond, msg)
Abnormal program termination if cond is false.
Definition: abort.h:131
#define NS_FATAL_ERROR(msg)
fatal error handling
Definition: fatal-error.h:72
void StartFlow(Ptr< Socket >, Ipv4Address, uint16_t)
void WriteUntilBufferFull(Ptr< Socket > localSocket, uint32_t txSpace)
Class for representing data rates.
Definition: data-rate.h:71
Packet header for IPv4.
Definition: ipv4-header.h:31
double GetSeconds(void) const
Definition: nstime.h:274
void EnablePcapAll(std::string prefix, bool promiscuous=false)
Enable pcap output on each device (which is of the appropriate type) in the set of all nodes created ...
int64_t GetMicroSeconds(void) const
Definition: nstime.h:291
void InstallAll(void) const
Aggregate IPv4, IPv6, UDP, and TCP stacks to all nodes in the simulation.
hold objects of type ns3::Time
Definition: nstime.h:961
A class representing a pcap file.
Definition: pcap-file.h:42
void Read(uint8_t *const data, uint32_t maxBytes, uint32_t &tsSec, uint32_t &tsUsec, uint32_t &inclLen, uint32_t &origLen, uint32_t &readLen)
Read next packet from file.
Definition: pcap-file.cc:437
Hold an unsigned integer type.
Definition: uinteger.h:46
#define NS_TEST_EXPECT_MSG_EQ(actual, limit, msg)
Test that an actual and expected (limit) value are equal and report if not.
Definition: test.h:244
holds a vector of ns3::NetDevice pointers
Callback< R > MakeCallback(R(T::*memPtr)(void), OBJ objPtr)
Definition: callback.h:1238
void Start(Time start)
Arrange for all of the Applications in this container to Start() at the Time given as a parameter...
virtual void DoRun(void)
Implementation to actually run this TestCase.
virtual void DoTeardown(void)
Implementation to do any local setup required for this TestCase.
virtual int Connect(const Address &address)=0
Initiate a connection to a remote host.
Ptr< Packet > Copy(void) const
Definition: packet.cc:122
void SetDefault(std::string name, const AttributeValue &value)
Definition: config.cc:667
virtual int Bind(const Address &address)=0
Allocate a local endpoint for this socket.
keep track of a set of node pointers.
hold objects of type Ptr
Definition: pointer.h:33
void WriteUntilBufferFull(Ptr< Socket >, uint32_t)
void SetList(const std::list< uint32_t > &packetlist)
Definition: error-model.cc:520
const uint32_t PCAP_LINK_TYPE
virtual void DoSetup(void)
Implementation to do any local setup required for this TestCase.
void Init(uint32_t dataLinkType, uint32_t snapLen=SNAPLEN_DEFAULT, int32_t timeZoneCorrection=ZONE_DEFAULT, bool swapMode=false)
Initialize the pcap file associated with this object.
Definition: pcap-file.cc:329
void Close(void)
Close the underlying file.
Definition: pcap-file.cc:86
void AddTestCase(TestCase *testCase) NS_DEPRECATED
Add an individual child TestCase case to this TestCase.
Definition: test.cc:173
void SetSendCallback(Callback< void, Ptr< Socket >, uint32_t > sendCb)
Notify application when space in transmit buffer is added.
Definition: socket.cc:121
static Ns3TcpStateTestSuite ns3TcpLossTestSuite
bool IsStatusSuccess(void) const
Definition: test.cc:330
void Open(std::string const &filename, std::ios::openmode mode)
Create a new pcap file or open an existing pcap file.
Definition: pcap-file.cc:310
const bool WRITE_LOGGING
void SetChannelAttribute(std::string name, const AttributeValue &value)
Set an attribute value to be propagated to each Channel created by the helper.
Ipv4 addresses are stored in host order in this class.
Definition: ipv4-address.h:38
void Stop(Time stop)
Arrange for all of the Applications in this container to Stop() at the Time given as a parameter...
Ipv4InterfaceContainer Assign(const NetDeviceContainer &c)
Assign IP addresses to the net devices specified in the container based on the current network prefix...
void Add(NodeContainer other)
Append the contents of another NodeContainer to the end of this container.
hold objects of type ns3::DataRate
Time Now(void)
create an ns3::Time instance which contains the current simulation time.
Definition: simulator.cc:287
Ptr< Node > Get(uint32_t i) const
Get the Ptr stored in this container at a given index.
uint32_t CopyData(uint8_t *buffer, uint32_t size) const
Copy the packet contents to a byte buffer.
Definition: packet.cc:381
ApplicationContainer Install(NodeContainer c) const
Install an ns3::PacketSinkApplication on each node of the input container configured with all the att...
A helper class to make life easier while doing simple IPv4 address assignment in scripts.
void EnableAsciiAll(std::string prefix)
Enable ascii trace output on each device (which is of the appropriate type) in the set of all nodes c...
void Create(uint32_t n)
Create n nodes and append pointers to them to the end of this NodeContainer.
uint32_t GetDataLinkType(void)
Definition: pcap-file.cc:135
void Write(uint32_t tsSec, uint32_t tsUsec, uint8_t const *const data, uint32_t totalLen)
Write next packet to file.
Definition: pcap-file.cc:404
virtual int Send(Ptr< Packet > p, uint32_t flags)=0
Send data (or dummy data) to the remote host.
virtual int Close(void)=0
Close a socket.
virtual uint32_t GetTxAvailable(void) const =0
Returns the number of bytes which can be sent in a single call to Send.
void Ipv4L3Tx(std::string context, Ptr< const Packet > packet, Ptr< Ipv4 > ipv4, uint32_t interface)
std::ostream * GetStream(void)
Return a pointer to an ostream previously set in the wrapper.
void SetBase(Ipv4Address network, Ipv4Mask mask, Ipv4Address base="0.0.0.1")
Set the base network number, network mask and base address.
void LogComponentEnable(char const *name, enum LogLevel level)
Definition: log.cc:311
const bool WRITE_VECTORS
Ipv4Address GetAddress(uint32_t i, uint32_t j=0) const
const uint32_t PCAP_SNAPLEN