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");
250  Ipv4InterfaceContainer interfaces = address.Assign (devices);
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:102
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
NetDeviceContainer Install(NodeContainer c)
A suite of tests to run.
Definition: test.h:1342
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:202
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:285
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:1155
void SetDeviceAttribute(std::string name, const AttributeValue &value)
Set an attribute value to be propagated to each NetDevice created by the helper.
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:34
a polymophic address class
Definition: address.h:90
Packet header for IPv4.
Definition: ipv4-header.h:33
nodes
Definition: first.py:25
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
Get an approximation of the time stored in this instance in the indicated unit.
Definition: nstime.h:363
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:28
holds a vector of ns3::NetDevice pointers
Callback< R > MakeCallback(R(T::*memPtr)(void), OBJ objPtr)
Definition: callback.h:1489
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:843
Ptr< Packet > Copy(void) const
performs a COW copy of the packet.
Definition: packet.cc:121
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:37
void SetTcp(std::string tid)
set the Tcp stack which will not need any other parameter.
void Install(std::string nodeName) const
Aggregate implementations of the ns3::Ipv4, ns3::Ipv6, ns3::Udp, and ns3::Tcp classes onto the provid...
const uint32_t PCAP_SNAPLEN
void Close(void)
Close the underlying file.
Definition: pcap-file.cc:88
bool IsStatusSuccess(void) const
Check if all tests passed.
Definition: test.cc:458
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 SetChannelAttribute(std::string name, const AttributeValue &value)
Set an attribute value to be propagated to each Channel created by the helper.
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...
#define NS_ABORT_MSG_UNLESS(cond, msg)
Abnormal program termination if a condition is false, with a message.
Definition: abort.h:144
Ptr< Node > Get(uint32_t i) const
Get the Ptr<Node> stored in this container at a given index.
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:1007
interfaces
Definition: first.py:41
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
uint32_t CopyData(uint8_t *buffer, uint32_t size) const
Copy the packet contents to a byte buffer.
Definition: packet.cc:378
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.
Time Now(void)
create an ns3::Time instance which contains the current simulation time.
Definition: simulator.cc:365
void Create(uint32_t n)
Create n nodes and append pointers to them to the end of this NodeContainer.
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:32
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
ApplicationContainer Install(NodeContainer c) const
Install an ns3::OnOffApplication on each node of the input container configured with all the attribut...
void Ipv4L3Tx(std::string context, Ptr< const Packet > packet, Ptr< Ipv4 > ipv4, uint32_t interface)
void SetAttribute(std::string name, const AttributeValue &value)
Helper function used to set the underlying application attributes.
static Ns3TcpInteroperabilityTestSuite ns3TcpInteroperabilityTestSuite
void SetBase(Ipv4Address network, Ipv4Mask mask, Ipv4Address base="0.0.0.1")
Set the base network number, network mask and base address.
Ipv4Address GetAddress(uint32_t i, uint32_t j=0) const