A Discrete-Event Network Simulator
API
ns3tcp-interop-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) 2009 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 <string>
20 
21 #include "ns3/log.h"
22 #include "ns3/abort.h"
23 #include "ns3/test.h"
24 #include "ns3/pcap-file.h"
25 #include "ns3/config.h"
26 #include "ns3/string.h"
27 #include "ns3/uinteger.h"
28 #include "ns3/inet-socket-address.h"
29 #include "ns3/point-to-point-helper.h"
30 #include "ns3/internet-stack-helper.h"
31 #include "ns3/ipv4-address-helper.h"
32 #include "ns3/ipv4-header.h"
33 #include "ns3/packet-sink-helper.h"
34 #include "ns3/on-off-helper.h"
35 #include "ns3/simulator.h"
36 
37 using namespace ns3;
38 
39 NS_LOG_COMPONENT_DEFINE ("Ns3TcpInteropTest");
40 
41 // The below boolean constants should only be changed to 'true'
42 // during test debugging (i.e. do not commit the value 'true')
43 
44 // set to 'true' to have the test suite overwrite the response vectors
45 // stored in the test directory. This should only be done if you are
46 // convinced through other means (e.g. pcap tracing or logging) that the
47 // revised vectors are the correct ones. In other words, don't simply
48 // enable this to true to clear a failing test without looking at the
49 // results closely.
50 const bool WRITE_VECTORS = false; // set to true to write response vectors
51 const bool WRITE_PCAP = false; // set to true to write out pcap
52 const uint32_t PCAP_LINK_TYPE = 1187373553; // Some large random number -- we use to verify data was written by this program
53 const uint32_t PCAP_SNAPLEN = 64; // Don't bother to save much data
54 
55 
56 // ===========================================================================
57 // This is a simple test to demonstrate how a known good model (a reference
58 // implementation) may be used to test another model in a relatively simple
59 // way.
60 //
61 // Node zero contains the model under test, in this case the ns-3 TCP
62 // implementation. Node one contains the reference implementation that we
63 // assume will generate good test vectors for us. In this case, a Linux
64 // TCP implementation is used to stimulate the ns-3 TCP model with what we
65 // assume are perfectly good packets. We watch the ns-3 implementation to
66 // see what it does in the presence of these assumed good stimuli.
67 //
68 // The test is arranged as a typical ns-3 script, but we use the trace system
69 // to peek into the running system and monitor the ns-3 TCP.
70 //
71 // The topology is just two nodes communicating over a point-to-point network.
72 // The point-to-point network is chosen because it is simple and allows us to
73 // easily generate pcap traces we can use to separately verify that the ns-3
74 // implementation is responding correctly. Once the operation is verified, we
75 // capture a set of response vectors that are then checked in the test to
76 // ensure that the ns-3 TCP continues to respond correctly over time.
77 //
78 // node 0 node 1
79 // +----------------+ +----------------+
80 // | ns-3 TCP | | Linux TCP |
81 // +----------------+ +----------------+
82 // | 10.1.1.1 | | 10.1.1.2 |
83 // +----------------+ +----------------+
84 // | point-to-point | | point-to-point |
85 // +----------------+ +----------------+
86 // | |
87 // +---------------------+
88 // 5 Mbps, 2 ms
89 //
90 // ===========================================================================
92 {
93 public:
96 
97 private:
98  virtual void DoSetup (void);
99  virtual void DoRun (void);
100  virtual void DoTeardown (void);
101 
102  void Ipv4L3Tx (std::string context, Ptr<const Packet> packet, Ptr<Ipv4> ipv4, uint32_t interface);
103 
104  std::string m_pcapFilename;
108 };
109 
111  : TestCase ("Check to see that the ns-3 TCP can work with liblinux2.6.26.so"), m_writeVectors (WRITE_VECTORS), m_writeResults (WRITE_PCAP)
112 {
113 }
114 
116 {
117 }
118 
119 void
121 {
122  //
123  // We expect there to be a file called tcp-interop-response-vectors.pcap in
124  // the data directory
125  //
126  m_pcapFilename = CreateDataDirFilename ("ns3tcp-interop-response-vectors.pcap");
127 
128  if (m_writeVectors)
129  {
130  m_pcapFile.Open (m_pcapFilename, std::ios::out|std::ios::binary);
132  }
133  else
134  {
135  m_pcapFile.Open (m_pcapFilename, std::ios::in|std::ios::binary);
136  NS_ABORT_MSG_UNLESS (m_pcapFile.GetDataLinkType () == PCAP_LINK_TYPE, "Wrong response vectors in directory");
137  }
138 }
139 
140 void
142 {
143  m_pcapFile.Close ();
144 }
145 
146 void
147 Ns3TcpInteroperabilityTestCase::Ipv4L3Tx (std::string context, Ptr<const Packet> packet, Ptr<Ipv4> ipv4, uint32_t interface)
148 {
149  //
150  // We're not testing IP so remove and toss the header. In order to do this,
151  // though, we need to copy the packet since we have a const version.
152  //
153  Ptr<Packet> p = packet->Copy ();
154  Ipv4Header ipHeader;
155  p->RemoveHeader (ipHeader);
156 
157  //
158  // What is left is the TCP header and any data that may be sent. We aren't
159  // sending any TCP data, so we expect what remains is only TCP header, which
160  // is a small thing to save.
161  //
162  if (m_writeVectors)
163  {
164  //
165  // Save the TCP under test response for later testing.
166  //
167  Time tNow = Simulator::Now ();
168  int64_t tMicroSeconds = tNow.GetMicroSeconds ();
169 
170  m_pcapFile.Write (uint32_t (tMicroSeconds / 1000000),
171  uint32_t (tMicroSeconds % 1000000),
172  p
173  );
174  }
175  else
176  {
177  //
178  // Read the TCP under test expected response from the expected vector
179  // file and see if it still does the right thing.
180  //
181  uint8_t expected[PCAP_SNAPLEN];
182  uint32_t tsSec, tsUsec, inclLen, origLen, readLen;
183  m_pcapFile.Read (expected, sizeof(expected), tsSec, tsUsec, inclLen, origLen, readLen);
184 
185  uint8_t *actual = new uint8_t[readLen];
186  p->CopyData (actual, readLen);
187 
188  uint32_t result = memcmp (actual, expected, readLen);
189 
190  delete [] actual;
191 
192  //
193  // Avoid streams of errors -- only report the first.
194  //
195  if (IsStatusSuccess ())
196  {
197  NS_TEST_EXPECT_MSG_EQ (result, 0, "Expected data comparison error");
198  }
199  }
200 }
201 
202 void
204 {
205  //
206  // Just create two nodes. One (node zero) will be the node with the TCP
207  // under test which is the ns-3 TCP implementation. The other node (node
208  // one) will be the node with the reference implementation we use to drive
209  // the tests.
210  //
212  nodes.Create (2);
213 
214  //
215  // For this test we'll use a point-to-point net device. It's not as simple
216  // as a simple-net-device, but it provides nice places to hook trace events
217  // so we can see what's moving between our nodes.
218  //
220  pointToPoint.SetDeviceAttribute ("DataRate", StringValue ("5Mbps"));
221  pointToPoint.SetChannelAttribute ("Delay", StringValue ("2ms"));
222 
223  //
224  // Install the point-to-point devices on both nodes and connec them up.
225  //
227  devices = pointToPoint.Install (nodes);
228 
229  //
230  // Install two variants of the internet stack. The first, on node zero
231  // uses the TCP under test, which is the default ns-3 TCP implementation.
232  //
234  stack.Install (nodes.Get (0));
235 
236  //
237  // The other node, node one, is going to be set up to use a Linux TCP
238  // implementation that we consider a known good TCP.
239  //
240  std::string nscStack = "liblinux2.6.26.so";
241  stack.SetTcp ("ns3::NscTcpL4Protocol", "Library", StringValue ("liblinux2.6.26.so"));
242  stack.Install (nodes.Get (1));
243 
244  //
245  // Assign the address 10.1.1.1 to the TCP implementation under test (index
246  // zero) and 10.1.1.2 to the reference implementation (index one).
247  //
249  address.SetBase ("10.1.1.0", "255.255.255.252");
251 
252  //
253  // We need a place for the TCP data to go on the node with the TCP under
254  // test, so just create a sink on node zero.
255  //
256  uint16_t sinkPort = 8080;
257  Address sinkAddress (InetSocketAddress (interfaces.GetAddress (0), sinkPort));
258  PacketSinkHelper packetSinkHelper ("ns3::TcpSocketFactory", InetSocketAddress (Ipv4Address::GetAny (), sinkPort));
259  ApplicationContainer sinkApps = packetSinkHelper.Install (nodes.Get (0));
260  sinkApps.Start (Seconds (0.));
261 
262  //
263  // We need something to shove data down the pipe, so we create an on-off
264  // application on the source node with the reference TCP implementation.
265  // The default behavior is to send for one second, then go quiet for one
266  // second, and repeat.
267  //
268  OnOffHelper onOffHelper ("ns3::TcpSocketFactory", sinkAddress);
269  onOffHelper.SetAttribute ("MaxBytes", UintegerValue (100000));
270  ApplicationContainer sourceApps = onOffHelper.Install (nodes.Get (1));
271  sourceApps.Start (Seconds (1.));
272  sourceApps.Stop (Seconds (10.));
273 
274  //
275  // There are currently a limited number of trace hooks in the ns-3 TCP code.
276  // Rather than editing TCP to insert a bunch of trace hooks, we can just
277  // intercept the packets at the IPv4 layer. See internet-stack-helper.cc
278  // for complete description of the trace hooks. We're interested in the
279  // responses of the TCP under test, which implies we need to hook the node
280  // zero Ipv4 layer three transmit trace source. We'll then get all of the
281  // responses we need
282  //
283  Config::Connect ("/NodeList/0/$ns3::Ipv4L3Protocol/Tx",
285 
286  //
287  // The idea here is that someone will look very closely at the all of the
288  // communications between the reference TCP and the TCP under test in this
289  // simulation and determine that all of the responses are correct. We expect
290  // that this means generating a pcap trace file from the point-to-point link
291  // and examining the packets closely using tcpdump, wireshark or some such
292  // program. So we provide the ability to generate a pcap trace of the
293  // test execution for your perusal.
294  //
295  // Once the validation test is determined to be running exactly as expected,
296  // we allow you to generate a file that contains the response vectors that
297  // will be checked during the actual execution of the test.
298  //
299 
300  if (m_writeResults)
301  {
302  pointToPoint.EnablePcapAll ("ns3-tcp-interop");
303  }
304 
305  Simulator::Stop (Seconds (20));
306  Simulator::Run ();
307  Simulator::Destroy ();
308 }
309 
311 {
312 public:
314 };
315 
317  : TestSuite ("ns3-tcp-interoperability", SYSTEM)
318 {
319  // We can't use NS_TEST_SOURCEDIR variable here because we use subdirectories
320  SetDataDir ("src/test/ns3tcp/response-vectors");
321 
322  AddTestCase (new Ns3TcpInteroperabilityTestCase, TestCase::QUICK);
323 }
324 
virtual void DoRun(void)
Implementation to actually run this TestCase.
uint32_t RemoveHeader(Header &header)
Deserialize and remove the header from the internal buffer.
Definition: packet.cc:280
holds a vector of ns3::Application pointers.
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:103
an Inet address class
holds a vector of std::pair of Ptr<Ipv4> and interface index.
Hold variables of type string.
Definition: string.h:41
A suite of tests to run.
Definition: test.h:1343
void Init(uint32_t dataLinkType, uint32_t snapLen=SNAPLEN_DEFAULT, int32_t timeZoneCorrection=ZONE_DEFAULT, bool swapMode=false, bool nanosecMode=false)
Initialize the pcap file associated with this object.
Definition: pcap-file.cc:345
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:205
ApplicationContainer Install(NodeContainer c) const
Install an ns3::PacketSinkApplication on each node of the input container configured with all the att...
aggregate IP/TCP/UDP functionality to existing Nodes.
#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:283
virtual void DoSetup(void)
Implementation to do any local setup required for this TestCase.
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:1153
A helper to make it easier to instantiate an ns3::OnOffApplication on a set of nodes.
Definition: on-off-helper.h:42
stack
Definition: first.py:41
a polymophic address class
Definition: address.h:90
bool IsStatusSuccess(void) const
Check if all tests passed.
Definition: test.cc:458
Packet header for IPv4.
Definition: ipv4-header.h:33
ApplicationContainer Install(NodeContainer c) const
Install an ns3::OnOffApplication on each node of the input container configured with all the attribut...
nodes
Definition: first.py:32
A class representing a pcap file.
Definition: pcap-file.h:42
void AddTestCase(TestCase *testCase, TestDuration duration=QUICK)
Add an individual child TestCase to this test suite.
Definition: test.cc:299
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:469
Hold an unsigned integer type.
Definition: uinteger.h:44
pointToPoint
Definition: first.py:35
holds a vector of ns3::NetDevice pointers
const bool WRITE_PCAP
const bool WRITE_VECTORS
void Start(Time start)
Arrange for all of the Applications in this container to Start() at the Time given as a parameter...
void Connect(std::string path, const CallbackBase &cb)
Definition: config.cc:920
int64_t GetMicroSeconds(void) const
Get an approximation of the time stored in this instance in the indicated unit.
Definition: nstime.h:388
Every class exported by the ns3 library is enclosed in the ns3 namespace.
keep track of a set of node pointers.
std::string CreateDataDirFilename(std::string filename)
Construct the full path to a file in the data directory.
Definition: test.cc:412
address
Definition: first.py:44
Ptr< Packet > Copy(void) const
performs a COW copy of the packet.
Definition: packet.cc:121
const uint32_t PCAP_SNAPLEN
void Close(void)
Close the underlying file.
Definition: pcap-file.cc:88
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:325
void Stop(Time stop)
Arrange for all of the Applications in this container to Stop() at the Time given as a parameter...
#define NS_ABORT_MSG_UNLESS(cond, msg)
Abnormal program termination if a condition is false, with a message.
Definition: abort.h:144
uint32_t CopyData(uint8_t *buffer, uint32_t size) const
Copy the packet contents to a byte buffer.
Definition: packet.cc:378
virtual void DoTeardown(void)
Implementation to do any local setup required for this TestCase.
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1289
interfaces
Definition: first.py:48
void SetDataDir(std::string directory)
Set the data directory where reference trace files can be found.
Definition: test.cc:465
const uint32_t PCAP_LINK_TYPE
A helper class to make life easier while doing simple IPv4 address assignment in scripts.
Time Now(void)
create an ns3::Time instance which contains the current simulation time.
Definition: simulator.cc:287
uint32_t GetDataLinkType(void)
Returns the data link type field of the pcap file as defined by the network field in the pcap global ...
Definition: pcap-file.cc:137
devices
Definition: first.py:39
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:434
void Ipv4L3Tx(std::string context, Ptr< const Packet > packet, Ptr< Ipv4 > ipv4, uint32_t interface)
Callback< R, Ts... > MakeCallback(R(T::*memPtr)(Ts...), OBJ objPtr)
Build Callbacks for class method members which take varying numbers of arguments and potentially retu...
Definition: callback.h:1642
void SetAttribute(std::string name, const AttributeValue &value)
Helper function used to set the underlying application attributes.
static Ns3TcpInteroperabilityTestSuite ns3TcpInteroperabilityTestSuite