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 "ns3/simple-net-device.h"
32 #include "ns3/simple-net-device-helper.h"
33 #include "ns3/socket.h"
34 #include "ns3/udp-socket.h"
35 
36 #include "ns3/log.h"
37 #include "ns3/node.h"
38 #include "ns3/inet-socket-address.h"
39 #include "ns3/boolean.h"
40 
41 #include "ns3/arp-l3-protocol.h"
42 #include "ns3/ipv4-l3-protocol.h"
43 #include "ns3/icmpv4-l4-protocol.h"
44 #include "ns3/ipv4-list-routing.h"
45 #include "ns3/ipv4-static-routing.h"
46 #include "ns3/udp-l4-protocol.h"
47 #include "ns3/internet-stack-helper.h"
48 #include "ns3/error-channel.h"
49 
50 #include <string>
51 #include <limits>
52 #include <netinet/in.h>
53 
54 using namespace ns3;
55 
56 class UdpSocketImpl;
57 
64 class IPv4TestTag : public Tag {
65 private:
66  uint64_t token;
67 public:
72  static TypeId GetTypeId () {
73  static TypeId tid = TypeId ("ns3::IPv4TestTag").SetParent<Tag> ().AddConstructor<IPv4TestTag> ();
74  return tid;
75  }
76  virtual TypeId GetInstanceTypeId () const { return GetTypeId (); }
77  virtual uint32_t GetSerializedSize () const { return sizeof (token); }
78  virtual void Serialize (TagBuffer buffer) const { buffer.WriteU64 (token); }
79  virtual void Deserialize (TagBuffer buffer) { token = buffer.ReadU64 (); }
80  virtual void Print (std::ostream &os) const { os << "token=" << token; }
85  void SetToken (uint64_t token) { this->token = token; }
90  uint64_t GetToken () { return token; }
91 };
92 
100 {
104 
105 
108  uint32_t m_dataSize;
109  uint8_t *m_data;
110  uint32_t m_size;
111  uint8_t m_icmpType;
112 
113 public:
114  virtual void DoRun (void);
117 
118  // server part
119 
124  void StartServer (Ptr<Node> ServerNode);
129  void HandleReadServer (Ptr<Socket> socket);
130 
131  // client part
132 
137  void StartClient (Ptr<Node> ClientNode);
142  void HandleReadClient (Ptr<Socket> socket);
151  void HandleReadIcmpClient (Ipv4Address icmpSource, uint8_t icmpTtl, uint8_t icmpType,
152  uint8_t icmpCode, uint32_t icmpInfo);
153 
160  void SetFill (uint8_t *fill, uint32_t fillSize, uint32_t dataSize);
161 
166  Ptr<Packet> SendClient (void);
167 
168 };
169 
171  : TestCase ("Verify the IPv4 layer 3 protocol fragmentation and reassembly")
172 {
173  m_socketServer = 0;
174  m_data = 0;
175  m_dataSize = 0;
176  m_size = 0;
177  m_icmpType = 0;
178 }
179 
181 {
182  if ( m_data )
183  {
184  delete[] m_data;
185  }
186  m_data = 0;
187  m_dataSize = 0;
188 }
189 
190 
191 void
193 {
194 
195  if (m_socketServer == 0)
196  {
197  TypeId tid = TypeId::LookupByName ("ns3::UdpSocketFactory");
198  m_socketServer = Socket::CreateSocket (ServerNode, tid);
199  InetSocketAddress local = InetSocketAddress (Ipv4Address::GetAny (), 9);
200  m_socketServer->Bind (local);
201  Ptr<UdpSocket> udpSocket = DynamicCast<UdpSocket> (m_socketServer);
202  if (udpSocket)
203  {
204  // equivalent to setsockopt (MCAST_JOIN_GROUP)
205  udpSocket->MulticastJoinGroup (0, Ipv4Address ("10.0.0.1"));
206  }
207  }
208 
210 }
211 
212 void
214 {
215  Ptr<Packet> packet;
216  Address from;
217  while ((packet = socket->RecvFrom (from)))
218  {
219  if (InetSocketAddress::IsMatchingType (from))
220  {
221  m_receivedPacketServer = packet->Copy();
222  }
223  }
224 }
225 
226 void
228 {
229 
230  if (m_socketClient == 0)
231  {
232  TypeId tid = TypeId::LookupByName ("ns3::UdpSocketFactory");
233  m_socketClient = Socket::CreateSocket (ClientNode, tid);
234  m_socketClient->Bind ();
237  m_socketClient->SetAttribute ("IcmpCallback", cbValue);
238  }
239 
241 }
242 
243 void
245 {
246  Ptr<Packet> packet;
247  Address from;
248  while ((packet = socket->RecvFrom (from)))
249  {
250  if (InetSocketAddress::IsMatchingType (from))
251  {
252  m_receivedPacketClient = packet->Copy();
253  }
254  }
255 }
256 
257 void
259  uint8_t icmpTtl, uint8_t icmpType,
260  uint8_t icmpCode, uint32_t icmpInfo)
261 {
262  m_icmpType = icmpType;
263 }
264 
265 void
266 Ipv4FragmentationTest::SetFill (uint8_t *fill, uint32_t fillSize, uint32_t dataSize)
267 {
268  if (dataSize != m_dataSize)
269  {
270  delete [] m_data;
271  m_data = new uint8_t [dataSize];
272  m_dataSize = dataSize;
273  }
274 
275  if (fillSize >= dataSize)
276  {
277  memcpy (m_data, fill, dataSize);
278  return;
279  }
280 
281  uint32_t filled = 0;
282  while (filled + fillSize < dataSize)
283  {
284  memcpy (&m_data[filled], fill, fillSize);
285  filled += fillSize;
286  }
287 
288  memcpy(&m_data[filled], fill, dataSize - filled);
289 
290  m_size = dataSize;
291 }
292 
294 {
295  Ptr<Packet> p;
296  if (m_dataSize)
297  {
298  p = Create<Packet> (m_data, m_dataSize);
299  }
300  else
301  {
302  p = Create<Packet> (m_size);
303  }
304  IPv4TestTag tag;
305  tag.SetToken (42);
306  p->AddPacketTag (tag);
307  p->AddByteTag (tag);
308 
309  m_socketClient->Send (p);
310 
311  return p;
312 }
313 
314 void
316 {
317  // set the arp cache to something quite high
318  // we shouldn't need because the NetDevice used doesn't need arp, but still
319  Config::SetDefault ("ns3::ArpCache::PendingQueueSize", UintegerValue (100));
320 
321  // Create topology
322 
323  // Receiver Node
324  Ptr<Node> serverNode = CreateObject<Node> ();
325  // Sender Node
326  Ptr<Node> clientNode = CreateObject<Node> ();
327 
328  NodeContainer nodes (serverNode, clientNode);
329 
330  Ptr<ErrorChannel> channel = CreateObject<ErrorChannel> ();
331  channel->SetJumpingTime (Seconds (0.5));
332 
333  SimpleNetDeviceHelper helperChannel;
334  helperChannel.SetNetDevicePointToPointMode (true);
335  NetDeviceContainer net = helperChannel.Install (nodes, channel);
336 
337  InternetStackHelper internet;
338  internet.Install (nodes);
339 
340  Ptr<Ipv4> ipv4;
341  uint32_t netdev_idx;
342  Ipv4InterfaceAddress ipv4Addr;
343 
344  // Receiver Node
345  ipv4 = serverNode->GetObject<Ipv4> ();
346  netdev_idx = ipv4->AddInterface (net.Get (0));
347  ipv4Addr = Ipv4InterfaceAddress (Ipv4Address ("10.0.0.1"), Ipv4Mask (0xffff0000U));
348  ipv4->AddAddress (netdev_idx, ipv4Addr);
349  ipv4->SetUp (netdev_idx);
350  Ptr<BinaryErrorModel> serverDevErrorModel = CreateObject<BinaryErrorModel> ();
351  Ptr<SimpleNetDevice> serverDev = DynamicCast<SimpleNetDevice> (net.Get (0));
352  serverDevErrorModel->Disable ();
353  serverDev->SetMtu(1500);
354  serverDev->SetReceiveErrorModel (serverDevErrorModel);
355  StartServer (serverNode);
356 
357  // Sender Node
358  ipv4 = clientNode->GetObject<Ipv4> ();
359  netdev_idx = ipv4->AddInterface (net.Get (1));
360  ipv4Addr = Ipv4InterfaceAddress (Ipv4Address ("10.0.0.2"), Ipv4Mask (0xffff0000U));
361  ipv4->AddAddress (netdev_idx, ipv4Addr);
362  ipv4->SetUp (netdev_idx);
363  Ptr<BinaryErrorModel> clientDevErrorModel = CreateObject<BinaryErrorModel> ();
364  Ptr<SimpleNetDevice> clientDev = DynamicCast<SimpleNetDevice> (net.Get (1));
365  clientDevErrorModel->Disable ();
366  clientDev->SetMtu(1500);
367  clientDev->SetReceiveErrorModel (clientDevErrorModel);
368  StartClient (clientNode);
369 
370  // some small packets, some rather big ones
371  uint32_t packetSizes[5] = {1000, 2000, 5000, 10000, 65000};
372 
373  // using the alphabet
374  uint8_t fillData[78];
375  for ( uint32_t k=48; k<=125; k++ )
376  {
377  fillData[k-48] = k;
378  }
379 
380  // First test: normal channel, no errors, no delays
381  for( int i= 0; i<5; i++)
382  {
383  uint32_t packetSize = packetSizes[i];
384 
385  SetFill (fillData, 78, packetSize);
386 
387  m_receivedPacketServer = Create<Packet> ();
388  Simulator::ScheduleWithContext (m_socketClient->GetNode ()->GetId (), Seconds (0),
390  Simulator::Run ();
391 
392  uint8_t recvBuffer[65000];
393 
394  uint16_t recvSize = m_receivedPacketServer->GetSize ();
395 
396  NS_TEST_EXPECT_MSG_EQ (recvSize, packetSizes[i], "Packet size not correct");
397 
398  m_receivedPacketServer->CopyData(recvBuffer, 65000);
400  0, "Packet content differs");
401  }
402 
403  // Second test: normal channel, no errors, delays each 2 packets.
404  // Each other fragment will arrive out-of-order.
405  // The packets should be received correctly since reassembly will reorder the fragments.
406  channel->SetJumpingMode(true);
407  for( int i= 0; i<5; i++)
408  {
409  uint32_t packetSize = packetSizes[i];
410 
411  SetFill (fillData, 78, packetSize);
412 
413  m_receivedPacketServer = Create<Packet> ();
414  Simulator::ScheduleWithContext (m_socketClient->GetNode ()->GetId (), Seconds (0),
416  Simulator::Run ();
417 
418  uint8_t recvBuffer[65000];
419 
420  uint16_t recvSize = m_receivedPacketServer->GetSize ();
421 
422  NS_TEST_EXPECT_MSG_EQ (recvSize, packetSizes[i], "Packet size not correct");
423 
424  m_receivedPacketServer->CopyData(recvBuffer, 65000);
426  0, "Packet content differs");
427  }
428  channel->SetJumpingMode(false);
429 
430  // Third test: normal channel, some errors, no delays.
431  // The reassembly procedure should fire a timeout after 30 seconds (as specified in the RFCs).
432  // Upon the timeout, the fragments received so far are discarded and an ICMP should be sent back
433  // to the sender (if the first fragment has been received).
434  // In this test case the first fragment is received, so we do expect an ICMP.
435  // Client -> Server : errors enabled
436  // Server -> Client : errors disabled (we want to have back the ICMP)
437  clientDevErrorModel->Disable();
438  serverDevErrorModel->Enable();
439  for( int i= 1; i<5; i++)
440  {
441  uint32_t packetSize = packetSizes[i];
442 
443  SetFill (fillData, 78, packetSize);
444 
445  // reset the model, we want to receive the very first fragment.
446  serverDevErrorModel->Reset();
447 
448  m_receivedPacketServer = Create<Packet> ();
449  m_icmpType = 0;
450  Simulator::ScheduleWithContext (m_socketClient->GetNode ()->GetId (), Seconds (0),
452  Simulator::Run ();
453 
454  uint16_t recvSize = m_receivedPacketServer->GetSize ();
455 
456  NS_TEST_EXPECT_MSG_EQ ((recvSize == 0), true, "Server got a packet, something wrong");
457  NS_TEST_EXPECT_MSG_EQ ((m_icmpType == 11), true, "Client did not receive ICMP::TIME_EXCEEDED");
458  }
459 
460  // Fourth test: normal channel, no errors, no delays.
461  // We check tags
462  clientDevErrorModel->Disable ();
463  serverDevErrorModel->Disable ();
464  for (int i= 0; i<5; i++)
465  {
466  uint32_t packetSize = packetSizes[i];
467 
468  SetFill (fillData, 78, packetSize);
469 
470  m_receivedPacketServer = Create<Packet> ();
471  Simulator::ScheduleWithContext (m_socketClient->GetNode ()->GetId (), Seconds (0),
473  Simulator::Run ();
474 
475  IPv4TestTag packetTag;
476  bool found = m_receivedPacketServer->PeekPacketTag (packetTag);
477 
478  NS_TEST_EXPECT_MSG_EQ (found, true, "PacketTag not found");
479  NS_TEST_EXPECT_MSG_EQ (packetTag.GetToken (), 42, "PacketTag value not correct");
480 
482 
483  uint32_t end = 0;
484  uint32_t tagStart = 0;
485  uint32_t tagEnd = 0;
486  while (iter.HasNext ())
487  {
488  ByteTagIterator::Item item = iter.Next ();
489  NS_TEST_EXPECT_MSG_EQ (item.GetTypeId ().GetName (), "ns3::IPv4TestTag", "ByteTag name not correct");
490  tagStart = item.GetStart ();
491  tagEnd = item.GetEnd ();
492  if (end == 0)
493  {
494  NS_TEST_EXPECT_MSG_EQ (tagStart, 0, "First ByteTag Start not correct");
495  }
496  if (end != 0)
497  {
498  NS_TEST_EXPECT_MSG_EQ (tagStart, end, "ByteTag End not correct");
499  }
500  end = tagEnd;
501  IPv4TestTag *byteTag = dynamic_cast<IPv4TestTag *> (item.GetTypeId ().GetConstructor () ());
502  NS_TEST_EXPECT_MSG_NE (byteTag, 0, "ByteTag not found");
503  item.GetTag (*byteTag);
504  NS_TEST_EXPECT_MSG_EQ (byteTag->GetToken (), 42, "ByteTag value not correct");
505  delete byteTag;
506  }
508  }
509 
510 
511  Simulator::Destroy ();
512 }
513 
514 
522 {
523 public:
525 };
526 
528  : TestSuite ("ipv4-fragmentation", UNIT)
529 {
530  AddTestCase (new Ipv4FragmentationTest, TestCase::QUICK);
531 }
532 
tuple channel
Definition: third.py:85
virtual uint32_t GetSerializedSize() const
virtual uint32_t AddInterface(Ptr< NetDevice > device)=0
an Inet address class
uint64_t GetToken()
Get the token.
void StartClient(Ptr< Node > ClientNode)
Start the client.
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:459
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:258
A suite of tests to run.
Definition: test.h:1342
void AddPacketTag(const Tag &tag) const
Add a packet tag.
Definition: packet.cc:814
Ptr< Packet > m_sentPacketClient
Packet sent by client.
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
uint32_t GetSize(void) const
Returns the the size in bytes of the packet (including the zero-filled initial payload).
Definition: packet.h:796
static TypeId GetTypeId()
Get the type ID.
encapsulates test code
Definition: test.h:1155
Ptr< Socket > m_socketServer
Server socket.
IPv4 Fragmentation TestSuite.
A sockets interface to UDP.
a polymophic address class
Definition: address.h:90
Callback< ObjectBase * > GetConstructor(void) const
Get the constructor callback.
Definition: type-id.cc:1052
AttributeValue implementation for Callback.
Definition: callback.h:1880
Ptr< Socket > m_socketClient
Client socket.
Ptr< Packet > SendClient(void)
Send a packet.
tuple nodes
Definition: first.py:25
Tag used in IPv4 Fragmentation Test.
bool PeekPacketTag(Tag &tag) const
Search a matching tag and call Tag::Deserialize if it is found.
Definition: packet.cc:836
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, TestDuration duration=QUICK)
Add an individual child TestCase to this test suite.
Definition: test.cc:299
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:791
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
static Ipv4FragmentationTestSuite g_ipv4fragmentationTestSuite
Static variable for test initialization.
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:121
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
IPv4 Fragmentation Test.
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...
void Reset(void)
Reset any state associated with the error model.
Definition: error-model.cc:118
#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:739
std::string GetName(void) const
Get the name.
Definition: type-id.cc:968
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)
Handle incoming ICMP packets.
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
uint32_t m_dataSize
Data size.
void StartServer(Ptr< Node > ServerNode)
Start the server.
Ipv4 addresses are stored in host order in this class.
Definition: ipv4-address.h:40
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.
uint32_t m_size
packet size.
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:993
void SetDefault(std::string name, const AttributeValue &value)
Definition: config.cc:782
void SetToken(uint64_t token)
Set the token.
Ptr< Packet > m_receivedPacketServer
Packet received by server.
uint64_t token
Token carried by the tag.
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:355
Ptr< Packet > m_receivedPacketClient
Packet received by client.
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:185
a unique identifier for an interface.
Definition: type-id.h:58
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:914
void Enable(void)
Enable the error model.
Definition: error-model.cc:125
void SetFill(uint8_t *fill, uint32_t fillSize, uint32_t dataSize)
Set the packet fill.
void HandleReadClient(Ptr< Socket > socket)
Handle incoming packets.
void AddByteTag(const Tag &tag) const
Tag each byte included in this packet with a new byte tag.
Definition: packet.cc:781
void HandleReadServer(Ptr< Socket > socket)
Handle incoming packets.