A Discrete-Event Network Simulator
API
ipv4-fragmentation-test.cc
Go to the documentation of this file.
1 /* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2011 Universita' di Firenze, Italy
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  * Author: Tommaso Pecorella <tommaso.pecorella@unifi.it>
19  */
24 #include "ns3/test.h"
25 #include "ns3/config.h"
26 #include "ns3/uinteger.h"
27 #include "ns3/socket-factory.h"
28 #include "ns3/ipv4-raw-socket-factory.h"
29 #include "ns3/udp-socket-factory.h"
30 #include "ns3/simulator.h"
31 #include "error-channel.h"
32 #include "ns3/simple-net-device.h"
33 #include "ns3/simple-net-device-helper.h"
34 #include "ns3/drop-tail-queue.h"
35 #include "ns3/socket.h"
36 #include "ns3/udp-socket.h"
37 
38 #include "ns3/log.h"
39 #include "ns3/node.h"
40 #include "ns3/inet-socket-address.h"
41 #include "ns3/boolean.h"
42 
43 #include "ns3/arp-l3-protocol.h"
44 #include "ns3/ipv4-l3-protocol.h"
45 #include "ns3/icmpv4-l4-protocol.h"
46 #include "ns3/ipv4-list-routing.h"
47 #include "ns3/ipv4-static-routing.h"
48 #include "ns3/udp-l4-protocol.h"
49 #include "ns3/internet-stack-helper.h"
50 
51 #include <string>
52 #include <limits>
53 #include <netinet/in.h>
54 
55 using namespace ns3;
56 
57 class UdpSocketImpl;
58 
59 /* ----------------------------------------------------------------------------------
60  * Tag
61  --------------------------------------------------------------------------------- */
62 class IPv4TestTag : public Tag {
63 private:
64  uint64_t token;
65 public:
66  static TypeId GetTypeId () {
67  static TypeId tid = TypeId ("ns3::IPv4TestTag").SetParent<Tag> ().AddConstructor<IPv4TestTag> ();
68  return tid;
69  }
70  virtual TypeId GetInstanceTypeId () const { return GetTypeId (); }
71  virtual uint32_t GetSerializedSize () const { return sizeof (token); }
72  virtual void Serialize (TagBuffer buffer) const { buffer.WriteU64 (token); }
73  virtual void Deserialize (TagBuffer buffer) { token = buffer.ReadU64 (); }
74  virtual void Print (std::ostream &os) const { os << "token=" << token; }
75  void setToken (uint64_t token) { this->token = token; }
76  uint64_t getToken () { return token; }
77 };
78 
80 {
84 
85 
88  uint32_t m_dataSize;
89  uint8_t *m_data;
90  uint32_t m_size;
91  uint8_t m_icmpType;
92 
93 public:
94  virtual void DoRun (void);
97 
98  // server part
99  void StartServer (Ptr<Node> ServerNode);
100  void HandleReadServer (Ptr<Socket> socket);
101 
102  // client part
103  void StartClient (Ptr<Node> ClientNode);
104  void HandleReadClient (Ptr<Socket> socket);
105  void HandleReadIcmpClient (Ipv4Address icmpSource, uint8_t icmpTtl, uint8_t icmpType,
106  uint8_t icmpCode,uint32_t icmpInfo);
107 
108  void SetFill (uint8_t *fill, uint32_t fillSize, uint32_t dataSize);
109  Ptr<Packet> SendClient (void);
110 
111 };
112 
113 
115  : TestCase ("Verify the IPv4 layer 3 protocol fragmentation and reassembly")
116 {
117  m_socketServer = 0;
118  m_data = 0;
119  m_dataSize = 0;
120 }
121 
123 {
124  if ( m_data )
125  {
126  delete[] m_data;
127  }
128  m_data = 0;
129  m_dataSize = 0;
130 }
131 
132 
133 void
135 {
136 
137  if (m_socketServer == 0)
138  {
139  TypeId tid = TypeId::LookupByName ("ns3::UdpSocketFactory");
140  m_socketServer = Socket::CreateSocket (ServerNode, tid);
141  InetSocketAddress local = InetSocketAddress (Ipv4Address::GetAny (), 9);
142  m_socketServer->Bind (local);
143  Ptr<UdpSocket> udpSocket = DynamicCast<UdpSocket> (m_socketServer);
144  if (udpSocket)
145  {
146  // equivalent to setsockopt (MCAST_JOIN_GROUP)
147  udpSocket->MulticastJoinGroup (0, Ipv4Address ("10.0.0.1"));
148  }
149  }
150 
152 }
153 
154 void
156 {
157  Ptr<Packet> packet;
158  Address from;
159  while ((packet = socket->RecvFrom (from)))
160  {
161  if (InetSocketAddress::IsMatchingType (from))
162  {
163  m_receivedPacketServer = packet->Copy();
164  }
165  }
166 }
167 
168 void
170 {
171 
172  if (m_socketClient == 0)
173  {
174  TypeId tid = TypeId::LookupByName ("ns3::UdpSocketFactory");
175  m_socketClient = Socket::CreateSocket (ClientNode, tid);
176  m_socketClient->Bind ();
179  m_socketClient->SetAttribute ("IcmpCallback", cbValue);
180  }
181 
183 }
184 
185 void
187 {
188  Ptr<Packet> packet;
189  Address from;
190  while ((packet = socket->RecvFrom (from)))
191  {
192  if (InetSocketAddress::IsMatchingType (from))
193  {
194  m_receivedPacketClient = packet->Copy();
195  }
196  }
197 }
198 
199 void
201  uint8_t icmpTtl, uint8_t icmpType,
202  uint8_t icmpCode, uint32_t icmpInfo)
203 {
204  m_icmpType = icmpType;
205 }
206 
207 void
208 Ipv4FragmentationTest::SetFill (uint8_t *fill, uint32_t fillSize, uint32_t dataSize)
209 {
210  if (dataSize != m_dataSize)
211  {
212  delete [] m_data;
213  m_data = new uint8_t [dataSize];
214  m_dataSize = dataSize;
215  }
216 
217  if (fillSize >= dataSize)
218  {
219  memcpy (m_data, fill, dataSize);
220  return;
221  }
222 
223  uint32_t filled = 0;
224  while (filled + fillSize < dataSize)
225  {
226  memcpy (&m_data[filled], fill, fillSize);
227  filled += fillSize;
228  }
229 
230  memcpy(&m_data[filled], fill, dataSize - filled);
231 
232  m_size = dataSize;
233 }
234 
236 {
237  Ptr<Packet> p;
238  if (m_dataSize)
239  {
240  p = Create<Packet> (m_data, m_dataSize);
241  }
242  else
243  {
244  p = Create<Packet> (m_size);
245  }
246  IPv4TestTag tag;
247  tag.setToken (42);
248  p->AddPacketTag (tag);
249  p->AddByteTag (tag);
250 
251  m_socketClient->Send (p);
252 
253  return p;
254 }
255 
256 void
258 {
259  // set the arp cache to something quite high
260  // we shouldn't need because the NetDevice used doesn't need arp, but still
261  Config::SetDefault ("ns3::ArpCache::PendingQueueSize", UintegerValue (100));
262 
263  // Create topology
264 
265  // Receiver Node
266  Ptr<Node> serverNode = CreateObject<Node> ();
267  // Sender Node
268  Ptr<Node> clientNode = CreateObject<Node> ();
269 
270  NodeContainer nodes (serverNode, clientNode);
271 
272  Ptr<ErrorChannel> channel = CreateObject<ErrorChannel> ();
273  channel->SetJumpingTime (Seconds (0.5));
274 
275  SimpleNetDeviceHelper helperChannel;
276  helperChannel.SetNetDevicePointToPointMode (true);
277  NetDeviceContainer net = helperChannel.Install (nodes, channel);
278 
279  InternetStackHelper internet;
280  internet.Install (nodes);
281 
282  Ptr<Ipv4> ipv4;
283  uint32_t netdev_idx;
284  Ipv4InterfaceAddress ipv4Addr;
285 
286  // Receiver Node
287  ipv4 = serverNode->GetObject<Ipv4> ();
288  netdev_idx = ipv4->AddInterface (net.Get (0));
289  ipv4Addr = Ipv4InterfaceAddress (Ipv4Address ("10.0.0.1"), Ipv4Mask (0xffff0000U));
290  ipv4->AddAddress (netdev_idx, ipv4Addr);
291  ipv4->SetUp (netdev_idx);
292  Ptr<BinaryErrorModel> serverDevErrorModel = CreateObject<BinaryErrorModel> ();
293  Ptr<SimpleNetDevice> serverDev = DynamicCast<SimpleNetDevice> (net.Get (0));
294  serverDevErrorModel->Disable ();
295  serverDev->SetMtu(1500);
296  serverDev->SetReceiveErrorModel (serverDevErrorModel);
297  StartServer (serverNode);
298 
299  // Sender Node
300  ipv4 = clientNode->GetObject<Ipv4> ();
301  netdev_idx = ipv4->AddInterface (net.Get (1));
302  ipv4Addr = Ipv4InterfaceAddress (Ipv4Address ("10.0.0.2"), Ipv4Mask (0xffff0000U));
303  ipv4->AddAddress (netdev_idx, ipv4Addr);
304  ipv4->SetUp (netdev_idx);
305  Ptr<BinaryErrorModel> clientDevErrorModel = CreateObject<BinaryErrorModel> ();
306  Ptr<SimpleNetDevice> clientDev = DynamicCast<SimpleNetDevice> (net.Get (1));
307  clientDevErrorModel->Disable ();
308  clientDev->SetMtu(1500);
309  clientDev->SetReceiveErrorModel (clientDevErrorModel);
310  StartClient (clientNode);
311 
312  // some small packets, some rather big ones
313  uint32_t packetSizes[5] = {1000, 2000, 5000, 10000, 65000};
314 
315  // using the alphabet
316  uint8_t fillData[78];
317  for ( uint32_t k=48; k<=125; k++ )
318  {
319  fillData[k-48] = k;
320  }
321 
322  // First test: normal channel, no errors, no delays
323  for( int i= 0; i<5; i++)
324  {
325  uint32_t packetSize = packetSizes[i];
326 
327  SetFill (fillData, 78, packetSize);
328 
329  m_receivedPacketServer = Create<Packet> ();
330  Simulator::ScheduleWithContext (m_socketClient->GetNode ()->GetId (), Seconds (0),
332  Simulator::Run ();
333 
334  uint8_t recvBuffer[65000];
335 
336  uint16_t recvSize = m_receivedPacketServer->GetSize ();
337 
338  NS_TEST_EXPECT_MSG_EQ (recvSize, packetSizes[i], "Packet size not correct");
339 
340  m_receivedPacketServer->CopyData(recvBuffer, 65000);
342  0, "Packet content differs");
343  }
344 
345  // Second test: normal channel, no errors, delays each 2 packets.
346  // Each other fragment will arrive out-of-order.
347  // The packets should be received correctly since reassembly will reorder the fragments.
348  channel->SetJumpingMode(true);
349  for( int i= 0; i<5; i++)
350  {
351  uint32_t packetSize = packetSizes[i];
352 
353  SetFill (fillData, 78, packetSize);
354 
355  m_receivedPacketServer = Create<Packet> ();
356  Simulator::ScheduleWithContext (m_socketClient->GetNode ()->GetId (), Seconds (0),
358  Simulator::Run ();
359 
360  uint8_t recvBuffer[65000];
361 
362  uint16_t recvSize = m_receivedPacketServer->GetSize ();
363 
364  NS_TEST_EXPECT_MSG_EQ (recvSize, packetSizes[i], "Packet size not correct");
365 
366  m_receivedPacketServer->CopyData(recvBuffer, 65000);
368  0, "Packet content differs");
369  }
370  channel->SetJumpingMode(false);
371 
372  // Third test: normal channel, some errors, no delays.
373  // The reassembly procedure should fire a timeout after 30 seconds (as specified in the RFCs).
374  // Upon the timeout, the fragments received so far are discarded and an ICMP should be sent back
375  // to the sender (if the first fragment has been received).
376  // In this test case the first fragment is received, so we do expect an ICMP.
377  // Client -> Server : errors enabled
378  // Server -> Client : errors disabled (we want to have back the ICMP)
379  clientDevErrorModel->Disable();
380  serverDevErrorModel->Enable();
381  for( int i= 1; i<5; i++)
382  {
383  uint32_t packetSize = packetSizes[i];
384 
385  SetFill (fillData, 78, packetSize);
386 
387  // reset the model, we want to receive the very first fragment.
388  serverDevErrorModel->Reset();
389 
390  m_receivedPacketServer = Create<Packet> ();
391  m_icmpType = 0;
392  Simulator::ScheduleWithContext (m_socketClient->GetNode ()->GetId (), Seconds (0),
394  Simulator::Run ();
395 
396  uint16_t recvSize = m_receivedPacketServer->GetSize ();
397 
398  NS_TEST_EXPECT_MSG_EQ ((recvSize == 0), true, "Server got a packet, something wrong");
399  NS_TEST_EXPECT_MSG_EQ ((m_icmpType == 11), true, "Client did not receive ICMP::TIME_EXCEEDED");
400  }
401 
402  // Fourth test: normal channel, no errors, no delays.
403  // We check tags
404  clientDevErrorModel->Disable ();
405  serverDevErrorModel->Disable ();
406  for (int i= 0; i<5; i++)
407  {
408  uint32_t packetSize = packetSizes[i];
409 
410  SetFill (fillData, 78, packetSize);
411 
412  m_receivedPacketServer = Create<Packet> ();
413  Simulator::ScheduleWithContext (m_socketClient->GetNode ()->GetId (), Seconds (0),
415  Simulator::Run ();
416 
417  IPv4TestTag packetTag;
418  bool found = m_receivedPacketServer->PeekPacketTag (packetTag);
419 
420  NS_TEST_EXPECT_MSG_EQ (found, true, "PacketTag not found");
421  NS_TEST_EXPECT_MSG_EQ (packetTag.getToken (), 42, "PacketTag value not correct");
422 
424 
425  uint32_t end = 0;
426  uint32_t tagStart = 0;
427  uint32_t tagEnd = 0;
428  while (iter.HasNext ())
429  {
430  ByteTagIterator::Item item = iter.Next ();
431  NS_TEST_EXPECT_MSG_EQ (item.GetTypeId ().GetName (), "ns3::IPv4TestTag", "ByteTag name not correct");
432  tagStart = item.GetStart ();
433  tagEnd = item.GetEnd ();
434  if (end == 0)
435  {
436  NS_TEST_EXPECT_MSG_EQ (tagStart, 0, "First ByteTag Start not correct");
437  }
438  if (end != 0)
439  {
440  NS_TEST_EXPECT_MSG_EQ (tagStart, end, "ByteTag End not correct");
441  }
442  end = tagEnd;
443  IPv4TestTag *byteTag = dynamic_cast<IPv4TestTag *> (item.GetTypeId ().GetConstructor () ());
444  NS_TEST_EXPECT_MSG_NE (byteTag, 0, "ByteTag not found");
445  item.GetTag (*byteTag);
446  NS_TEST_EXPECT_MSG_EQ (byteTag->getToken (), 42, "ByteTag value not correct");
447  delete byteTag;
448  }
450  }
451 
452 
453  Simulator::Destroy ();
454 }
455 //-----------------------------------------------------------------------------
457 {
458 public:
459  Ipv4FragmentationTestSuite () : TestSuite ("ipv4-fragmentation", UNIT)
460  {
461  AddTestCase (new Ipv4FragmentationTest, TestCase::QUICK);
462  }
tuple channel
Definition: third.py:85
virtual uint32_t GetSerializedSize() const
virtual uint32_t AddInterface(Ptr< NetDevice > device)=0
an Inet address class
void StartClient(Ptr< Node > ClientNode)
NetDeviceContainer Install(Ptr< Node > node) const
This method creates an ns3::SimpleChannel with the attributes configured by SimpleNetDeviceHelper::Se...
Ptr< T > GetObject(void) const
Get a pointer to the requested aggregated Object.
Definition: object.h:462
void WriteU64(uint64_t v)
Definition: tag-buffer.cc:102
Ptr< NetDevice > Get(uint32_t i) const
Get the Ptr stored in this container at a given index.
a class to represent an Ipv4 address mask
Definition: ipv4-address.h:257
A suite of tests to run.
Definition: test.h:1333
void AddPacketTag(const Tag &tag) const
Add a packet tag.
Definition: packet.cc:824
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
uint32_t GetSize(void) const
Returns the the size in bytes of the packet (including the zero-filled initial payload).
Definition: packet.h:792
static TypeId GetTypeId()
encapsulates test code
Definition: test.h:1147
This test suite implements a Unit Test.
Definition: test.h:1343
A sockets interface to UDP.
void setToken(uint64_t token)
a polymophic address class
Definition: address.h:90
Callback< ObjectBase * > GetConstructor(void) const
Get the constructor callback.
Definition: type-id.cc:1042
AttributeValue implementation for Callback.
Definition: callback.h:1880
Ptr< Packet > SendClient(void)
tuple nodes
Definition: first.py:25
bool PeekPacketTag(Tag &tag) const
Search a matching tag and call Tag::Deserialize if it is found.
Definition: packet.cc:846
Identifies a byte tag and a set of bytes within a packet to which the tag applies.
Definition: packet.h:61
virtual int MulticastJoinGroup(uint32_t interface, const Address &groupAddress)=0
Corresponds to socket option MCAST_JOIN_GROUP.
void AddTestCase(TestCase *testCase, enum TestDuration duration)
Add an individual child TestCase to this test suite.
Definition: test.cc:298
virtual void Deserialize(TagBuffer buffer)
virtual void SetUp(uint32_t interface)=0
Hold an unsigned integer type.
Definition: uinteger.h:44
holds a vector of ns3::NetDevice pointers
Callback< R > MakeCallback(R(T::*memPtr)(void), OBJ objPtr)
Definition: callback.h:1489
ByteTagIterator GetByteTagIterator(void) const
Returns an iterator over the set of byte tags included in this packet.
Definition: packet.cc:801
void SetRecvCallback(Callback< void, Ptr< Socket > >)
Notify application when new data is available to be read.
Definition: socket.cc:128
uint32_t GetEnd(void) const
The index is an offset from the start of the packet.
Definition: packet.cc:44
void Disable(void)
Disable the error model.
Definition: error-model.cc:132
virtual int Connect(const Address &address)=0
Initiate a connection to a remote host.
void SetJumpingMode(bool mode)
Set if the odd packets are delayed (even ones are not delayed ever)
Access to the IPv4 forwarding table, interfaces, and configuration.
Definition: ipv4.h:76
virtual void Serialize(TagBuffer buffer) const
Ptr< Packet > Copy(void) const
performs a COW copy of the packet.
Definition: packet.cc:122
tag a set of bytes in a packet
Definition: tag.h:36
virtual int Bind(const Address &address)=0
Allocate a local endpoint for this socket.
Every class exported by the ns3 library is enclosed in the ns3 namespace.
keep track of a set of node pointers.
uint64_t ReadU64(void)
Definition: tag-buffer.cc:134
void SetNetDevicePointToPointMode(bool pointToPointMode)
SimpleNetDevice is Broadcast capable and ARP needing.
Iterator over the set of byte tags in a packet.
Definition: packet.h:54
void Install(std::string nodeName) const
Aggregate implementations of the ns3::Ipv4, ns3::Ipv6, ns3::Udp, and ns3::Tcp classes onto the provid...
#define NS_TEST_EXPECT_MSG_NE(actual, limit, msg)
Test that an actual and expected (limit) value are not equal and report if not.
Definition: test.h:732
std::string GetName(void) const
Get the name.
Definition: type-id.cc:958
virtual void Print(std::ostream &os) const
TypeId GetTypeId(void) const
Definition: packet.cc:34
void HandleReadIcmpClient(Ipv4Address icmpSource, uint8_t icmpTtl, uint8_t icmpType, uint8_t icmpCode, uint32_t icmpInfo)
virtual TypeId GetInstanceTypeId() const
Get the most derived TypeId for this Object.
void GetTag(Tag &tag) const
Read the requested tag and store it in the user-provided tag instance.
Definition: packet.cc:49
void StartServer(Ptr< Node > ServerNode)
Ipv4 addresses are stored in host order in this class.
Definition: ipv4-address.h:40
Ipv4FragmentationTestSuite g_ipv4fragmentationTestSuite
read and write tag data
Definition: tag-buffer.h:51
uint32_t GetStart(void) const
The index is an offset from the start of the packet.
Definition: packet.cc:39
uint32_t GetId(void) const
Definition: node.cc:107
a class to store IPv4 address information on an interface
virtual Ptr< Node > GetNode(void) const =0
Return the node this socket is associated with.
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:895
void SetDefault(std::string name, const AttributeValue &value)
Definition: config.cc:774
virtual bool AddAddress(uint32_t interface, Ipv4InterfaceAddress address)=0
uint32_t CopyData(uint8_t *buffer, uint32_t size) const
Copy the packet contents to a byte buffer.
Definition: packet.cc:356
virtual void DoRun(void)
Implementation to actually run this TestCase.
void SetJumpingTime(Time delay)
Set the delay for the odd packets (even ones are not delayed)
static const uint32_t packetSize
virtual Ptr< Packet > RecvFrom(uint32_t maxSize, uint32_t flags, Address &fromAddress)=0
Read a single packet from the socket and retrieve the sender address.
build a set of SimpleNetDevice objects
virtual int Send(Ptr< Packet > p, uint32_t flags)=0
Send data (or dummy data) to the remote host.
void SetAttribute(std::string name, const AttributeValue &value)
Set a single attribute, raising fatal errors if unsuccessful.
Definition: object-base.cc:191
a unique identifier for an interface.
Definition: type-id.h:58
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:904
void Enable(void)
Enable the error model.
Definition: error-model.cc:125
void SetFill(uint8_t *fill, uint32_t fillSize, uint32_t dataSize)
void HandleReadClient(Ptr< Socket > socket)
void AddByteTag(const Tag &tag) const
Tag each byte included in this packet with a new byte tag.
Definition: packet.cc:791
void HandleReadServer(Ptr< Socket > socket)