A Discrete-Event Network Simulator
API
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
ns3tcp-interop-test-suite.cc
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 opration 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;
95  PcapFile m_pcapFile;
96  bool m_writeVectors;
97 };
98 
99 Ns3TcpInteroperabilityTestCase::Ns3TcpInteroperabilityTestCase ()
100  : TestCase ("Check to see that the ns-3 TCP can work with liblinux2.6.26.so"), m_writeVectors (WRITE_VECTORS)
101 {
102 }
103 
104 Ns3TcpInteroperabilityTestCase::~Ns3TcpInteroperabilityTestCase ()
105 {
106 }
107 
108 void
110 {
111  //
112  // We expect there to be a file called tcp-interop-response-vectors.pcap in
113  // response-vectors/ of this directory
114  //
115  m_pcapFilename = static_cast<std::string> (NS_TEST_SOURCEDIR) +
116  static_cast<std::string> ("/response-vectors/ns3tcp-interop-response-vectors.pcap");
117 
118  if (m_writeVectors)
119  {
120  m_pcapFile.Open (m_pcapFilename, std::ios::out|std::ios::binary);
121  m_pcapFile.Init (PCAP_LINK_TYPE, PCAP_SNAPLEN);
122  }
123  else
124  {
125  m_pcapFile.Open (m_pcapFilename, std::ios::in|std::ios::binary);
126  NS_ABORT_MSG_UNLESS (m_pcapFile.GetDataLinkType () == PCAP_LINK_TYPE, "Wrong response vectors in directory");
127  }
128 }
129 
130 void
132 {
133  m_pcapFile.Close ();
134 }
135 
136 void
137 Ns3TcpInteroperabilityTestCase::Ipv4L3Tx (std::string context, Ptr<const Packet> packet, Ptr<Ipv4> ipv4, uint32_t interface)
138 {
139  //
140  // We're not testing IP so remove and toss the header. In order to do this,
141  // though, we need to copy the packet since we have a const version.
142  //
143  Ptr<Packet> p = packet->Copy ();
144  Ipv4Header ipHeader;
145  p->RemoveHeader (ipHeader);
146 
147  //
148  // What is left is the TCP header and any data that may be sent. We aren't
149  // sending any TCP data, so we expect what remains is only TCP header, which
150  // is a small thing to save.
151  //
152  if (m_writeVectors)
153  {
154  //
155  // Save the TCP under test response for later testing.
156  //
157  Time tNow = Simulator::Now ();
158  int64_t tMicroSeconds = tNow.GetMicroSeconds ();
159 
160  uint32_t size = p->GetSize ();
161  uint8_t *buf = new uint8_t[size];
162  p->CopyData (buf, size);
163 
164  m_pcapFile.Write (uint32_t (tMicroSeconds / 1000000),
165  uint32_t (tMicroSeconds % 1000000),
166  buf,
167  size);
168  delete [] buf;
169  }
170  else
171  {
172  //
173  // Read the TCP under test expected response from the expected vector
174  // file and see if it still does the right thing.
175  //
176  uint8_t expected[PCAP_SNAPLEN];
177  uint32_t tsSec, tsUsec, inclLen, origLen, readLen;
178  m_pcapFile.Read (expected, sizeof(expected), tsSec, tsUsec, inclLen, origLen, readLen);
179 
180  uint8_t *actual = new uint8_t[readLen];
181  p->CopyData (actual, readLen);
182 
183  uint32_t result = memcmp (actual, expected, readLen);
184 
185  delete [] actual;
186 
187  //
188  // Avoid streams of errors -- only report the first.
189  //
190  if (IsStatusSuccess ())
191  {
192  NS_TEST_EXPECT_MSG_EQ (result, 0, "Expected data comparison error");
193  }
194  }
195 }
196 
197 void
199 {
200  //
201  // Just create two nodes. One (node zero) will be the node with the TCP
202  // under test which is the ns-3 TCP implementation. The other node (node
203  // one) will be the node with the reference implementation we use to drive
204  // the tests.
205  //
206  NodeContainer nodes;
207  nodes.Create (2);
208 
209  //
210  // For this test we'll use a point-to-point net device. It's not as simple
211  // as a simple-net-device, but it provides nice places to hook trace events
212  // so we can see what's moving between our nodes.
213  //
214  PointToPointHelper pointToPoint;
215  pointToPoint.SetDeviceAttribute ("DataRate", StringValue ("5Mbps"));
216  pointToPoint.SetChannelAttribute ("Delay", StringValue ("2ms"));
217 
218  //
219  // Install the point-to-point devices on both nodes and connec them up.
220  //
221  NetDeviceContainer devices;
222  devices = pointToPoint.Install (nodes);
223 
224  //
225  // Install two variants of the internet stack. The first, on node zero
226  // uses the TCP under test, which is the default ns-3 TCP implementation.
227  //
228  InternetStackHelper stack;
229  stack.Install (nodes.Get (0));
230 
231  //
232  // The other node, node one, is going to be set up to use a Linux TCP
233  // implementation that we consider a known good TCP.
234  //
235  std::string nscStack = "liblinux2.6.26.so";
236  stack.SetTcp ("ns3::NscTcpL4Protocol", "Library", StringValue ("liblinux2.6.26.so"));
237  stack.Install (nodes.Get (1));
238 
239  //
240  // Assign the address 10.1.1.1 to the TCP implementation under test (index
241  // zero) and 10.1.1.2 to the reference implementation (index one).
242  //
243  Ipv4AddressHelper address;
244  address.SetBase ("10.1.1.0", "255.255.255.252");
245  Ipv4InterfaceContainer interfaces = address.Assign (devices);
246 
247  //
248  // We need a place for the TCP data to go on the node with the TCP under
249  // test, so just create a sink on node zero.
250  //
251  uint16_t sinkPort = 8080;
252  Address sinkAddress (InetSocketAddress (interfaces.GetAddress (0), sinkPort));
253  PacketSinkHelper packetSinkHelper ("ns3::TcpSocketFactory", InetSocketAddress (Ipv4Address::GetAny (), sinkPort));
254  ApplicationContainer sinkApps = packetSinkHelper.Install (nodes.Get (0));
255  sinkApps.Start (Seconds (0.));
256 
257  //
258  // We need something to shove data down the pipe, so we create an on-off
259  // application on the soure node with the reference TCP implementation.
260  // The default behavior is to send for one second, then go quiet for one
261  // second, and repeat.
262  //
263  OnOffHelper onOffHelper ("ns3::TcpSocketFactory", sinkAddress);
264  onOffHelper.SetAttribute ("MaxBytes", UintegerValue (100000));
265  ApplicationContainer sourceApps = onOffHelper.Install (nodes.Get (1));
266  sourceApps.Start (Seconds (1.));
267  sourceApps.Stop (Seconds (10.));
268 
269  //
270  // There are currently a limited number of trace hooks in the ns-3 TCP code.
271  // Rather than editing TCP to insert a bunch of trace hooks, we can just
272  // intercept the packets at the IPv4 layer. See internet-stack-helper.cc
273  // for complete description of the trace hooks. We're interested in the
274  // responses of the TCP under test, which implies we need to hook the node
275  // zero Ipv4 layer three transmit trace source. We'll then get all of the
276  // responses we need
277  //
278  Config::Connect ("/NodeList/0/$ns3::Ipv4L3Protocol/Tx",
279  MakeCallback (&Ns3TcpInteroperabilityTestCase::Ipv4L3Tx, this));
280 
281  //
282  // The idea here is that someone will look very closely at the all of the
283  // communications between the reference TCP and the TCP under test in this
284  // simulation and determine that all of the responses are correct. We expect
285  // that this means generating a pcap trace file from the point-to-point link
286  // and examining the packets closely using tcpdump, wireshark or some such
287  // program. So we provide the ability to generate a pcap trace of the
288  // test execution for your perusal.
289  //
290  // Once the validation test is determined to be running exactly as exptected,
291  // we allow you to generate a file that contains the response vectors that
292  // will be checked during the actual execution of the test.
293  //
294 
295  if (m_writeVectors)
296  {
297  pointToPoint.EnablePcapAll ("tcp-interop");
298  }
299 
300  Simulator::Stop (Seconds (20));
301  Simulator::Run ();
302  Simulator::Destroy ();
303 }
304 
306 {
307 public:
309 };
310 
311 Ns3TcpInteroperabilityTestSuite::Ns3TcpInteroperabilityTestSuite ()
312  : TestSuite ("ns3-tcp-interoperability", SYSTEM)
313 {
314  AddTestCase (new Ns3TcpInteroperabilityTestCase, TestCase::QUICK);
315 }
316 
317 static Ns3TcpInteroperabilityTestSuite ns3TcpInteroperabilityTestSuite;
virtual void DoRun(void)
Implementation to actually run this test case.
uint32_t RemoveHeader(Header &header)
Definition: packet.cc:285
holds a vector of ns3::Application pointers.
keep track of time unit.
Definition: nstime.h:149
an Inet address class
holds a vector of std::pair of Ptr<Ipv4> and interface index.
hold variables of type string
Definition: string.h:19
NetDeviceContainer Install(NodeContainer c)
A suite of tests to run.
Definition: test.h:962
#define NS_LOG_COMPONENT_DEFINE(name)
Definition: log.h:122
aggregate IP/TCP/UDP functionality to existing Nodes.
uint32_t GetSize(void) const
Definition: packet.h:620
virtual void DoSetup(void)
Implementation to do any local setup required for this test case.
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:834
void SetDeviceAttribute(std::string name, const AttributeValue &value)
A helper to make it easier to instantiate an ns3::OnOffApplication on a set of nodes.
Definition: on-off-helper.h:41
#define NS_ABORT_MSG_UNLESS(cond, msg)
Abnormal program termination if cond is false.
Definition: abort.h:131
a polymophic address class
Definition: address.h:86
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
Definition: nstime.h:279
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:438
Hold an unsigned integer type.
Definition: uinteger.h:46
holds a vector of ns3::NetDevice pointers
Callback< R > MakeCallback(R(T::*memPtr)(void), OBJ objPtr)
Definition: callback.h:502
void Start(Time start)
Arrange for all of the Applications in this container to Start() at the Time given as a parameter...
Ptr< Packet > Copy(void) const
Definition: packet.cc:131
keep track of a set of node pointers.
void SetTcp(std::string tid)
set the Tcp stack which will not need any other parameter.
void Install(std::string nodeName) const
void Init(uint32_t dataLinkType, uint32_t snapLen=SNAPLEN_DEFAULT, int32_t timeZoneCorrection=ZONE_DEFAULT, bool swapMode=false)
Definition: pcap-file.cc:330
void Close(void)
Definition: pcap-file.cc:87
void AddTestCase(TestCase *testCase) NS_DEPRECATED
Add an individual test case to this test suite.
Definition: test.cc:172
bool IsStatusSuccess(void) const
Definition: test.cc:329
void Open(std::string const &filename, std::ios::openmode mode)
Definition: pcap-file.cc:311
void SetChannelAttribute(std::string name, const AttributeValue &value)
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...
Time Seconds(double seconds)
create ns3::Time instances in units of seconds.
Definition: nstime.h:586
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 test case.
uint32_t CopyData(uint8_t *buffer, uint32_t size) const
Definition: packet.cc:398
ApplicationContainer Install(NodeContainer c) const
A helper class to make life easier while doing simple IPv4 address assignment in scripts.
void Create(uint32_t n)
Create n nodes and append pointers to them to the end of this NodeContainer.
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:405
ApplicationContainer Install(NodeContainer c) const
void SetAttribute(std::string name, const AttributeValue &value)
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