A Discrete-Event Network Simulator
API
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
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/drop-tail-queue.h"
34 #include "ns3/socket.h"
35 #include "ns3/udp-socket.h"
36 
37 #include "ns3/log.h"
38 #include "ns3/node.h"
39 #include "ns3/inet-socket-address.h"
40 #include "ns3/boolean.h"
41 
42 #include "ns3/arp-l3-protocol.h"
43 #include "ns3/ipv4-l3-protocol.h"
44 #include "ns3/icmpv4-l4-protocol.h"
45 #include "ns3/ipv4-list-routing.h"
46 #include "ns3/ipv4-static-routing.h"
47 #include "ns3/udp-l4-protocol.h"
48 
49 #include <string>
50 #include <limits>
51 #include <netinet/in.h>
52 
53 using namespace ns3;
54 
55 class UdpSocketImpl;
56 
57 /* ----------------------------------------------------------------------------------
58  * Tag
59  --------------------------------------------------------------------------------- */
60 class IPv4TestTag : public Tag {
61 private:
62  uint64_t token;
63 public:
64  static TypeId GetTypeId () {
65  static TypeId tid = TypeId ("ns3::IPv4TestTag").SetParent<Tag> ().AddConstructor<IPv4TestTag> ();
66  return tid;
67  }
68  virtual TypeId GetInstanceTypeId () const { return GetTypeId (); }
69  virtual uint32_t GetSerializedSize () const { return sizeof (token); }
70  virtual void Serialize (TagBuffer buffer) const { buffer.WriteU64 (token); }
71  virtual void Deserialize (TagBuffer buffer) { token = buffer.ReadU64 (); }
72  virtual void Print (std::ostream &os) const { os << "token=" << token; }
73  void setToken (uint64_t token) { this->token = token; }
74  uint64_t getToken () { return token; }
75 };
76 
77 static void
79 {
80  //ARP
81  Ptr<ArpL3Protocol> arp = CreateObject<ArpL3Protocol> ();
82  node->AggregateObject(arp);
83  //IPV4
84  Ptr<Ipv4L3Protocol> ipv4 = CreateObject<Ipv4L3Protocol> ();
85  //Routing for Ipv4
86  Ptr<Ipv4ListRouting> ipv4Routing = CreateObject<Ipv4ListRouting> ();
87  ipv4->SetRoutingProtocol (ipv4Routing);
88  Ptr<Ipv4StaticRouting> ipv4staticRouting = CreateObject<Ipv4StaticRouting> ();
89  ipv4Routing->AddRoutingProtocol (ipv4staticRouting, 0);
90  node->AggregateObject(ipv4);
91  //ICMP
92  Ptr<Icmpv4L4Protocol> icmp = CreateObject<Icmpv4L4Protocol> ();
93  node->AggregateObject(icmp);
94  // //Ipv4Raw
95  Ptr<UdpL4Protocol> udp = CreateObject<UdpL4Protocol> ();
96  node->AggregateObject(udp);
97 }
98 
99 
101 {
105 
106 
109  uint32_t m_dataSize;
110  uint8_t *m_data;
111  uint32_t m_size;
112  uint8_t m_icmpType;
113 
114 public:
115  virtual void DoRun (void);
118 
119  // server part
120  void StartServer (Ptr<Node> ServerNode);
121  void HandleReadServer (Ptr<Socket> socket);
122 
123  // client part
124  void StartClient (Ptr<Node> ClientNode);
125  void HandleReadClient (Ptr<Socket> socket);
126  void HandleReadIcmpClient (Ipv4Address icmpSource, uint8_t icmpTtl, uint8_t icmpType,
127  uint8_t icmpCode,uint32_t icmpInfo);
128 
129  void SetFill (uint8_t *fill, uint32_t fillSize, uint32_t dataSize);
130  Ptr<Packet> SendClient (void);
131 
132 };
133 
134 
136  : TestCase ("Verify the IPv4 layer 3 protocol fragmentation and reassembly")
137 {
138  m_socketServer = 0;
139  m_data = 0;
140  m_dataSize = 0;
141 }
142 
144 {
145  if ( m_data )
146  {
147  delete[] m_data;
148  }
149  m_data = 0;
150  m_dataSize = 0;
151 }
152 
153 
154 void
156 {
157 
158  if (m_socketServer == 0)
159  {
160  TypeId tid = TypeId::LookupByName ("ns3::UdpSocketFactory");
161  m_socketServer = Socket::CreateSocket (ServerNode, tid);
162  InetSocketAddress local = InetSocketAddress (Ipv4Address::GetAny (), 9);
163  m_socketServer->Bind (local);
164  Ptr<UdpSocket> udpSocket = DynamicCast<UdpSocket> (m_socketServer);
165  if (udpSocket)
166  {
167  // equivalent to setsockopt (MCAST_JOIN_GROUP)
168  udpSocket->MulticastJoinGroup (0, Ipv4Address ("10.0.0.1"));
169  }
170  }
171 
173 }
174 
175 void
177 {
178  Ptr<Packet> packet;
179  Address from;
180  while ((packet = socket->RecvFrom (from)))
181  {
182  if (InetSocketAddress::IsMatchingType (from))
183  {
184  m_receivedPacketServer = packet->Copy();
185  }
186  }
187 }
188 
189 void
191 {
192 
193  if (m_socketClient == 0)
194  {
195  TypeId tid = TypeId::LookupByName ("ns3::UdpSocketFactory");
196  m_socketClient = Socket::CreateSocket (ClientNode, tid);
197  m_socketClient->Bind ();
200  m_socketClient->SetAttribute ("IcmpCallback", cbValue);
201  }
202 
204 }
205 
206 void
208 {
209  Ptr<Packet> packet;
210  Address from;
211  while ((packet = socket->RecvFrom (from)))
212  {
213  if (InetSocketAddress::IsMatchingType (from))
214  {
215  m_receivedPacketClient = packet->Copy();
216  }
217  }
218 }
219 
220 void
222  uint8_t icmpTtl, uint8_t icmpType,
223  uint8_t icmpCode, uint32_t icmpInfo)
224 {
225  m_icmpType = icmpType;
226 }
227 
228 void
229 Ipv4FragmentationTest::SetFill (uint8_t *fill, uint32_t fillSize, uint32_t dataSize)
230 {
231  if (dataSize != m_dataSize)
232  {
233  delete [] m_data;
234  m_data = new uint8_t [dataSize];
235  m_dataSize = dataSize;
236  }
237 
238  if (fillSize >= dataSize)
239  {
240  memcpy (m_data, fill, dataSize);
241  return;
242  }
243 
244  uint32_t filled = 0;
245  while (filled + fillSize < dataSize)
246  {
247  memcpy (&m_data[filled], fill, fillSize);
248  filled += fillSize;
249  }
250 
251  memcpy(&m_data[filled], fill, dataSize - filled);
252 
253  m_size = dataSize;
254 }
255 
257 {
258  Ptr<Packet> p;
259  if (m_dataSize)
260  {
261  p = Create<Packet> (m_data, m_dataSize);
262  }
263  else
264  {
265  p = Create<Packet> (m_size);
266  }
267  IPv4TestTag tag;
268  tag.setToken (42);
269  p->AddPacketTag (tag);
270  p->AddByteTag (tag);
271 
272  m_socketClient->Send (p);
273 
274  return p;
275 }
276 
277 void
279 {
280  // set the arp cache to something quite high
281  // we shouldn't need because the NetDevice used doesn't need arp, but still
282  Config::SetDefault ("ns3::ArpCache::PendingQueueSize", UintegerValue (100));
283 
284  // Create topology
285 
286  // Receiver Node
287  Ptr<Node> serverNode = CreateObject<Node> ();
288  AddInternetStack (serverNode);
289  Ptr<SimpleNetDevice> serverDev;
290  Ptr<BinaryErrorModel> serverDevErrorModel = CreateObject<BinaryErrorModel> ();
291  {
292  serverDev = CreateObject<SimpleNetDevice> ();
293  serverDev->SetAddress (Mac48Address::ConvertFrom (Mac48Address::Allocate ()));
294  serverDev->SetMtu(1500);
295  serverDev->SetReceiveErrorModel(serverDevErrorModel);
296  serverDevErrorModel->Disable();
297  serverNode->AddDevice (serverDev);
298  Ptr<Ipv4> ipv4 = serverNode->GetObject<Ipv4> ();
299  uint32_t netdev_idx = ipv4->AddInterface (serverDev);
300  Ipv4InterfaceAddress ipv4Addr = Ipv4InterfaceAddress (Ipv4Address ("10.0.0.1"), Ipv4Mask (0xffff0000U));
301  ipv4->AddAddress (netdev_idx, ipv4Addr);
302  ipv4->SetUp (netdev_idx);
303  }
304  StartServer(serverNode);
305 
306  // Sender Node
307  Ptr<Node> clientNode = CreateObject<Node> ();
308  AddInternetStack (clientNode);
309  Ptr<SimpleNetDevice> clientDev;
310  Ptr<BinaryErrorModel> clientDevErrorModel = CreateObject<BinaryErrorModel> ();
311  {
312  clientDev = CreateObject<SimpleNetDevice> ();
313  clientDev->SetAddress (Mac48Address::ConvertFrom (Mac48Address::Allocate ()));
314  clientDev->SetMtu(1000);
315  clientDev->SetReceiveErrorModel(clientDevErrorModel);
316  clientDevErrorModel->Disable();
317  clientNode->AddDevice (clientDev);
318  Ptr<Ipv4> ipv4 = clientNode->GetObject<Ipv4> ();
319  uint32_t netdev_idx = ipv4->AddInterface (clientDev);
320  Ipv4InterfaceAddress ipv4Addr = Ipv4InterfaceAddress (Ipv4Address ("10.0.0.2"), Ipv4Mask (0xffff0000U));
321  ipv4->AddAddress (netdev_idx, ipv4Addr);
322  ipv4->SetUp (netdev_idx);
323  }
324  StartClient(clientNode);
325 
326  // link the two nodes
327  Ptr<ErrorChannel> channel = CreateObject<ErrorChannel> ();
328  serverDev->SetChannel (channel);
329  clientDev->SetChannel (channel);
330  channel->SetJumpingTime(Seconds(0.5));
331 
332 
333  // some small packets, some rather big ones
334  uint32_t packetSizes[5] = {1000, 2000, 5000, 10000, 65000};
335 
336  // using the alphabet
337  uint8_t fillData[78];
338  for ( uint32_t k=48; k<=125; k++ )
339  {
340  fillData[k-48] = k;
341  }
342 
343  // First test: normal channel, no errors, no delays
344  for( int i= 0; i<5; i++)
345  {
346  uint32_t packetSize = packetSizes[i];
347 
348  SetFill (fillData, 78, packetSize);
349 
350  m_receivedPacketServer = Create<Packet> ();
351  Simulator::ScheduleWithContext (m_socketClient->GetNode ()->GetId (), Seconds (0),
353  Simulator::Run ();
354 
355  uint8_t recvBuffer[65000];
356 
357  uint16_t recvSize = m_receivedPacketServer->GetSize ();
358 
359  NS_TEST_EXPECT_MSG_EQ (recvSize, packetSizes[i], "Packet size not correct");
360 
361  m_receivedPacketServer->CopyData(recvBuffer, 65000);
363  0, "Packet content differs");
364  }
365 
366  // Second test: normal channel, no errors, delays each 2 packets.
367  // Each other fragment will arrive out-of-order.
368  // The packets should be received correctly since reassembly will reorder the fragments.
369  channel->SetJumpingMode(true);
370  for( int i= 0; i<5; i++)
371  {
372  uint32_t packetSize = packetSizes[i];
373 
374  SetFill (fillData, 78, packetSize);
375 
376  m_receivedPacketServer = Create<Packet> ();
377  Simulator::ScheduleWithContext (m_socketClient->GetNode ()->GetId (), Seconds (0),
379  Simulator::Run ();
380 
381  uint8_t recvBuffer[65000];
382 
383  uint16_t recvSize = m_receivedPacketServer->GetSize ();
384 
385  NS_TEST_EXPECT_MSG_EQ (recvSize, packetSizes[i], "Packet size not correct");
386 
387  m_receivedPacketServer->CopyData(recvBuffer, 65000);
389  0, "Packet content differs");
390  }
391  channel->SetJumpingMode(false);
392 
393  // Third test: normal channel, some errors, no delays.
394  // The reassembly procedure should fire a timeout after 30 seconds (as specified in the RFCs).
395  // Upon the timeout, the fragments received so far are discarded and an ICMP should be sent back
396  // to the sender (if the first fragment has been received).
397  // In this test case the first fragment is received, so we do expect an ICMP.
398  // Client -> Server : errors enabled
399  // Server -> Client : errors disabled (we want to have back the ICMP)
400  clientDevErrorModel->Disable();
401  serverDevErrorModel->Enable();
402  for( int i= 1; i<5; i++)
403  {
404  uint32_t packetSize = packetSizes[i];
405 
406  SetFill (fillData, 78, packetSize);
407 
408  // reset the model, we want to receive the very first fragment.
409  serverDevErrorModel->Reset();
410 
411  m_receivedPacketServer = Create<Packet> ();
412  m_icmpType = 0;
413  Simulator::ScheduleWithContext (m_socketClient->GetNode ()->GetId (), Seconds (0),
415  Simulator::Run ();
416 
417  uint16_t recvSize = m_receivedPacketServer->GetSize ();
418 
419  NS_TEST_EXPECT_MSG_EQ ((recvSize == 0), true, "Server got a packet, something wrong");
420  NS_TEST_EXPECT_MSG_EQ ((m_icmpType == 11), true, "Client did not receive ICMP::TIME_EXCEEDED");
421  }
422 
423  // Fourth test: normal channel, no errors, no delays.
424  // We check tags
425  clientDevErrorModel->Disable ();
426  serverDevErrorModel->Disable ();
427  for (int i= 0; i<5; i++)
428  {
429  uint32_t packetSize = packetSizes[i];
430 
431  SetFill (fillData, 78, packetSize);
432 
433  m_receivedPacketServer = Create<Packet> ();
434  Simulator::ScheduleWithContext (m_socketClient->GetNode ()->GetId (), Seconds (0),
436  Simulator::Run ();
437 
438  IPv4TestTag packetTag;
439  bool found = m_receivedPacketServer->PeekPacketTag (packetTag);
440 
441  NS_TEST_EXPECT_MSG_EQ (found, true, "PacketTag not found");
442  NS_TEST_EXPECT_MSG_EQ (packetTag.getToken (), 42, "PacketTag value not correct");
443 
445 
446  uint32_t end = 0;
447  uint32_t tagStart = 0;
448  uint32_t tagEnd = 0;
449  while (iter.HasNext ())
450  {
451  ByteTagIterator::Item item = iter.Next ();
452  NS_TEST_EXPECT_MSG_EQ (item.GetTypeId ().GetName (), "ns3::IPv4TestTag", "ByteTag name not correct");
453  tagStart = item.GetStart ();
454  tagEnd = item.GetEnd ();
455  if (end == 0)
456  {
457  NS_TEST_EXPECT_MSG_EQ (tagStart, 0, "First ByteTag Start not correct");
458  }
459  if (end != 0)
460  {
461  NS_TEST_EXPECT_MSG_EQ (tagStart, end, "ByteTag End not correct");
462  }
463  end = tagEnd;
464  IPv4TestTag *byteTag = dynamic_cast<IPv4TestTag *> (item.GetTypeId ().GetConstructor () ());
465  NS_TEST_EXPECT_MSG_NE (byteTag, 0, "ByteTag not found");
466  item.GetTag (*byteTag);
467  NS_TEST_EXPECT_MSG_EQ (byteTag->getToken (), 42, "ByteTag value not correct");
468  delete byteTag;
469  }
471  }
472 
473 
474  Simulator::Destroy ();
475 }
476 //-----------------------------------------------------------------------------
478 {
479 public:
480  Ipv4FragmentationTestSuite () : TestSuite ("ipv4-fragmentation", UNIT)
481  {
482  AddTestCase (new Ipv4FragmentationTest, TestCase::QUICK);
483  }
virtual uint32_t GetSerializedSize() const
virtual uint32_t AddInterface(Ptr< NetDevice > device)=0
an Inet address class
void StartClient(Ptr< Node > ClientNode)
void WriteU64(uint64_t v)
Definition: tag-buffer.cc:102
a class to represent an Ipv4 address mask
Definition: ipv4-address.h:222
A suite of tests to run.
Definition: test.h:1105
void AddPacketTag(const Tag &tag) const
Add a packet tag.
Definition: packet.cc:841
#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:265
uint32_t GetSize(void) const
Returns the the size in bytes of the packet (including the zero-filled initial payload).
Definition: packet.h:744
static TypeId GetTypeId()
encapsulates test code
Definition: test.h:929
A sockets interface to UDP.
void setToken(uint64_t token)
a polymophic address class
Definition: address.h:86
Callback< ObjectBase * > GetConstructor(void) const
Definition: type-id.cc:722
AttributeValue form of a Callback.
Definition: callback.h:1662
Ptr< Packet > SendClient(void)
bool PeekPacketTag(Tag &tag) const
Search a matching tag and call Tag::Deserialize if it is found.
Definition: packet.cc:863
Identifies a byte tag and a set of bytes within a packet to which the tag applies.
Definition: packet.h:57
virtual int MulticastJoinGroup(uint32_t interface, const Address &groupAddress)=0
Corresponds to socket option MCAST_JOIN_GROUP.
virtual void Deserialize(TagBuffer buffer)
virtual void SetUp(uint32_t interface)=0
Hold an unsigned integer type.
Definition: uinteger.h:46
virtual bool SetMtu(const uint16_t mtu)
Callback< R > MakeCallback(R(T::*memPtr)(void), OBJ objPtr)
Definition: callback.h:1242
ByteTagIterator GetByteTagIterator(void) const
Retiurns an iterator over the set of byte tags included in this packet.
Definition: packet.cc:818
void SetRecvCallback(Callback< void, Ptr< Socket > >)
Notify application when new data is available to be read.
Definition: socket.cc:127
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:131
void AggregateObject(Ptr< Object > other)
Definition: object.cc:242
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
void SetDefault(std::string name, const AttributeValue &value)
Definition: config.cc:667
virtual int Bind(const Address &address)=0
Allocate a local endpoint for this socket.
uint64_t ReadU64(void)
Definition: tag-buffer.cc:134
Iterator over the set of byte tags in a packet.
Definition: packet.h:50
#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:704
std::string GetName(void) const
Definition: type-id.cc:657
virtual void Print(std::ostream &os) const
void SetReceiveErrorModel(Ptr< ErrorModel > em)
Attach a receive ErrorModel to the SimpleNetDevice.
TypeId GetTypeId(void) const
Definition: packet.cc:34
static void AddInternetStack(Ptr< Node > node)
void AddTestCase(TestCase *testCase) NS_DEPRECATED
Add an individual child TestCase case to this TestCase.
Definition: test.cc:184
void HandleReadIcmpClient(Ipv4Address icmpSource, uint8_t icmpTtl, uint8_t icmpType, uint8_t icmpCode, uint32_t icmpInfo)
virtual TypeId GetInstanceTypeId() const
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:38
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 AddDevice(Ptr< NetDevice > device)
Definition: node.cc:120
uint32_t GetId(void) const
Definition: node.cc:106
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.
virtual void SetAddress(Address address)
Set the address of this interface.
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:381
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)
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.
This test suite implements a Unit Test.
Definition: test.h:1115
virtual int Send(Ptr< Packet > p, uint32_t flags)=0
Send data (or dummy data) to the remote host.
void SetChannel(Ptr< SimpleChannel > channel)
Attach a channel to this net device.
void SetAttribute(std::string name, const AttributeValue &value)
Definition: object-base.cc:176
Ptr< T > GetObject(void) const
Definition: object.h:362
a unique identifier for an interface.
Definition: type-id.h:49
TypeId SetParent(TypeId tid)
Definition: type-id.cc:610
void Enable(void)
Enable the error model.
Definition: error-model.cc:124
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:808
void HandleReadServer(Ptr< Socket > socket)
void SetRoutingProtocol(Ptr< Ipv4RoutingProtocol > routingProtocol)
Register a new routing protocol to be used by this Ipv4 stack.