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 const bool WRITE_VECTORS = false; // set to true to write response vectors
42 const uint32_t PCAP_LINK_TYPE = 1187373553; // Some large random number -- we use to verify data was written by this program
43 const uint32_t PCAP_SNAPLEN = 64; // Don't bother to save much data
44 
45 
46 // ===========================================================================
47 // This is a simple test to demonstrate how a known good model (a reference
48 // implementation) may be used to test another model in a relatively simple
49 // way.
50 //
51 // Node zero contains the model under test, in this case the ns-3 TCP
52 // implementation. Node one contains the reference implementation that we
53 // assume will generate good test vectors for us. In this case, a Linux
54 // TCP implementation is used to stimulate the ns-3 TCP model with what we
55 // assume are perfectly good packets. We watch the ns-3 implementation to
56 // see what it does in the presence of these assumed good stimuli.
57 //
58 // The test is arranged as a typical ns-3 script, but we use the trace system
59 // to peek into the running system and monitor the ns-3 TCP.
60 //
61 // The topology is just two nodes communicating over a point-to-point network.
62 // The point-to-point network is chosen because it is simple and allows us to
63 // easily generate pcap traces we can use to separately verify that the ns-3
64 // implementation is responding correctly. Once the operation is verified, we
65 // capture a set of response vectors that are then checked in the test to
66 // ensure that the ns-3 TCP continues to respond correctly over time.
67 //
68 // node 0 node 1
69 // +----------------+ +----------------+
70 // | ns-3 TCP | | Linux TCP |
71 // +----------------+ +----------------+
72 // | 10.1.1.1 | | 10.1.1.2 |
73 // +----------------+ +----------------+
74 // | point-to-point | | point-to-point |
75 // +----------------+ +----------------+
76 // | |
77 // +---------------------+
78 // 5 Mbps, 2 ms
79 //
80 // ===========================================================================
82 {
83 public:
86 
87 private:
88  virtual void DoSetup (void);
89  virtual void DoRun (void);
90  virtual void DoTeardown (void);
91 
92  void Ipv4L3Tx (std::string context, Ptr<const Packet> packet, Ptr<Ipv4> ipv4, uint32_t interface);
93 
94  std::string m_pcapFilename;
97 };
98 
100  : TestCase ("Check to see that the ns-3 TCP can work with liblinux2.6.26.so"), m_writeVectors (WRITE_VECTORS)
101 {
102 }
103 
105 {
106 }
107 
108 void
110 {
111  //
112  // We expect there to be a file called tcp-interop-response-vectors.pcap in
113  // the data directory
114  //
115  m_pcapFilename = CreateDataDirFilename ("ns3tcp-interop-response-vectors.pcap");
116 
117  if (m_writeVectors)
118  {
119  m_pcapFile.Open (m_pcapFilename, std::ios::out|std::ios::binary);
121  }
122  else
123  {
124  m_pcapFile.Open (m_pcapFilename, std::ios::in|std::ios::binary);
125  NS_ABORT_MSG_UNLESS (m_pcapFile.GetDataLinkType () == PCAP_LINK_TYPE, "Wrong response vectors in directory");
126  }
127 }
128 
129 void
131 {
132  m_pcapFile.Close ();
133 }
134 
135 void
136 Ns3TcpInteroperabilityTestCase::Ipv4L3Tx (std::string context, Ptr<const Packet> packet, Ptr<Ipv4> ipv4, uint32_t interface)
137 {
138  //
139  // We're not testing IP so remove and toss the header. In order to do this,
140  // though, we need to copy the packet since we have a const version.
141  //
142  Ptr<Packet> p = packet->Copy ();
143  Ipv4Header ipHeader;
144  p->RemoveHeader (ipHeader);
145 
146  //
147  // What is left is the TCP header and any data that may be sent. We aren't
148  // sending any TCP data, so we expect what remains is only TCP header, which
149  // is a small thing to save.
150  //
151  if (m_writeVectors)
152  {
153  //
154  // Save the TCP under test response for later testing.
155  //
156  Time tNow = Simulator::Now ();
157  int64_t tMicroSeconds = tNow.GetMicroSeconds ();
158 
159  m_pcapFile.Write (uint32_t (tMicroSeconds / 1000000),
160  uint32_t (tMicroSeconds % 1000000),
161  p
162  );
163  }
164  else
165  {
166  //
167  // Read the TCP under test expected response from the expected vector
168  // file and see if it still does the right thing.
169  //
170  uint8_t expected[PCAP_SNAPLEN];
171  uint32_t tsSec, tsUsec, inclLen, origLen, readLen;
172  m_pcapFile.Read (expected, sizeof(expected), tsSec, tsUsec, inclLen, origLen, readLen);
173 
174  uint8_t *actual = new uint8_t[readLen];
175  p->CopyData (actual, readLen);
176 
177  uint32_t result = memcmp (actual, expected, readLen);
178 
179  delete [] actual;
180 
181  //
182  // Avoid streams of errors -- only report the first.
183  //
184  if (IsStatusSuccess ())
185  {
186  NS_TEST_EXPECT_MSG_EQ (result, 0, "Expected data comparison error");
187  }
188  }
189 }
190 
191 void
193 {
194  //
195  // Just create two nodes. One (node zero) will be the node with the TCP
196  // under test which is the ns-3 TCP implementation. The other node (node
197  // one) will be the node with the reference implementation we use to drive
198  // the tests.
199  //
201  nodes.Create (2);
202 
203  //
204  // For this test we'll use a point-to-point net device. It's not as simple
205  // as a simple-net-device, but it provides nice places to hook trace events
206  // so we can see what's moving between our nodes.
207  //
209  pointToPoint.SetDeviceAttribute ("DataRate", StringValue ("5Mbps"));
210  pointToPoint.SetChannelAttribute ("Delay", StringValue ("2ms"));
211 
212  //
213  // Install the point-to-point devices on both nodes and connec them up.
214  //
216  devices = pointToPoint.Install (nodes);
217 
218  //
219  // Install two variants of the internet stack. The first, on node zero
220  // uses the TCP under test, which is the default ns-3 TCP implementation.
221  //
223  stack.Install (nodes.Get (0));
224 
225  //
226  // The other node, node one, is going to be set up to use a Linux TCP
227  // implementation that we consider a known good TCP.
228  //
229  std::string nscStack = "liblinux2.6.26.so";
230  stack.SetTcp ("ns3::NscTcpL4Protocol", "Library", StringValue ("liblinux2.6.26.so"));
231  stack.Install (nodes.Get (1));
232 
233  //
234  // Assign the address 10.1.1.1 to the TCP implementation under test (index
235  // zero) and 10.1.1.2 to the reference implementation (index one).
236  //
238  address.SetBase ("10.1.1.0", "255.255.255.252");
239  Ipv4InterfaceContainer interfaces = address.Assign (devices);
240 
241  //
242  // We need a place for the TCP data to go on the node with the TCP under
243  // test, so just create a sink on node zero.
244  //
245  uint16_t sinkPort = 8080;
246  Address sinkAddress (InetSocketAddress (interfaces.GetAddress (0), sinkPort));
247  PacketSinkHelper packetSinkHelper ("ns3::TcpSocketFactory", InetSocketAddress (Ipv4Address::GetAny (), sinkPort));
248  ApplicationContainer sinkApps = packetSinkHelper.Install (nodes.Get (0));
249  sinkApps.Start (Seconds (0.));
250 
251  //
252  // We need something to shove data down the pipe, so we create an on-off
253  // application on the soure node with the reference TCP implementation.
254  // The default behavior is to send for one second, then go quiet for one
255  // second, and repeat.
256  //
257  OnOffHelper onOffHelper ("ns3::TcpSocketFactory", sinkAddress);
258  onOffHelper.SetAttribute ("MaxBytes", UintegerValue (100000));
259  ApplicationContainer sourceApps = onOffHelper.Install (nodes.Get (1));
260  sourceApps.Start (Seconds (1.));
261  sourceApps.Stop (Seconds (10.));
262 
263  //
264  // There are currently a limited number of trace hooks in the ns-3 TCP code.
265  // Rather than editing TCP to insert a bunch of trace hooks, we can just
266  // intercept the packets at the IPv4 layer. See internet-stack-helper.cc
267  // for complete description of the trace hooks. We're interested in the
268  // responses of the TCP under test, which implies we need to hook the node
269  // zero Ipv4 layer three transmit trace source. We'll then get all of the
270  // responses we need
271  //
272  Config::Connect ("/NodeList/0/$ns3::Ipv4L3Protocol/Tx",
274 
275  //
276  // The idea here is that someone will look very closely at the all of the
277  // communications between the reference TCP and the TCP under test in this
278  // simulation and determine that all of the responses are correct. We expect
279  // that this means generating a pcap trace file from the point-to-point link
280  // and examining the packets closely using tcpdump, wireshark or some such
281  // program. So we provide the ability to generate a pcap trace of the
282  // test execution for your perusal.
283  //
284  // Once the validation test is determined to be running exactly as expected,
285  // we allow you to generate a file that contains the response vectors that
286  // will be checked during the actual execution of the test.
287  //
288 
289  if (m_writeVectors)
290  {
291  pointToPoint.EnablePcapAll ("tcp-interop");
292  }
293 
294  Simulator::Stop (Seconds (20));
295  Simulator::Run ();
296  Simulator::Destroy ();
297 }
298 
300 {
301 public:
303 };
304 
306  : TestSuite ("ns3-tcp-interoperability", SYSTEM)
307 {
308  // We can't use NS_TEST_SOURCEDIR variable here because we use subdirectories
309  SetDataDir ("src/test/ns3tcp/response-vectors");
310 
311  AddTestCase (new Ns3TcpInteroperabilityTestCase, TestCase::QUICK);
312 }
313 
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:268
holds a vector of ns3::Application pointers.
tuple pointToPoint
Definition: first.py:28
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:102
an Inet address class
tuple devices
Definition: first.py:32
holds a vector of std::pair of Ptr 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:1333
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:201
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:278
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:1147
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
a polymophic address class
Definition: address.h:90
tuple nodes
Definition: first.py:25
Packet header for IPv4.
Definition: ipv4-header.h:31
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:349
void AddTestCase(TestCase *testCase, enum TestDuration duration)
Add an individual child TestCase to this test suite.
Definition: test.cc:297
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:469
Hold an unsigned integer type.
Definition: uinteger.h:44
tuple interfaces
Definition: first.py:41
holds a vector of ns3::NetDevice pointers
Callback< R > MakeCallback(R(T::*memPtr)(void), OBJ objPtr)
Definition: callback.h:1480
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:835
Ptr< Packet > Copy(void) const
performs a COW copy of the packet.
Definition: packet.cc:122
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:410
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:456
tuple stack
Definition: first.py:34
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 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:895
void SetDataDir(std::string directory)
Set the data directory where reference trace files can be found.
Definition: test.cc:463
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:356
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:330
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
tuple address
Definition: first.py:37
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