A Discrete-Event Network Simulator
API
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
ipv4-fragmentation-test.cc
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 "error-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 static void
58 AddInternetStack (Ptr<Node> node)
59 {
60  //ARP
61  Ptr<ArpL3Protocol> arp = CreateObject<ArpL3Protocol> ();
62  node->AggregateObject(arp);
63  //IPV4
64  Ptr<Ipv4L3Protocol> ipv4 = CreateObject<Ipv4L3Protocol> ();
65  //Routing for Ipv4
66  Ptr<Ipv4ListRouting> ipv4Routing = CreateObject<Ipv4ListRouting> ();
67  ipv4->SetRoutingProtocol (ipv4Routing);
68  Ptr<Ipv4StaticRouting> ipv4staticRouting = CreateObject<Ipv4StaticRouting> ();
69  ipv4Routing->AddRoutingProtocol (ipv4staticRouting, 0);
70  node->AggregateObject(ipv4);
71  //ICMP
72  Ptr<Icmpv4L4Protocol> icmp = CreateObject<Icmpv4L4Protocol> ();
73  node->AggregateObject(icmp);
74  // //Ipv4Raw
75  Ptr<UdpL4Protocol> udp = CreateObject<UdpL4Protocol> ();
76  node->AggregateObject(udp);
77 }
78 
79 
81 {
82  Ptr<Packet> m_sentPacketClient;
83  Ptr<Packet> m_receivedPacketClient;
84  Ptr<Packet> m_receivedPacketServer;
85 
86 
87  Ptr<Socket> m_socketServer;
88  Ptr<Socket> m_socketClient;
89  uint32_t m_dataSize;
90  uint8_t *m_data;
91  uint32_t m_size;
92  uint8_t m_icmpType;
93 
94 public:
95  virtual void DoRun (void);
98 
99  // server part
100  void StartServer (Ptr<Node> ServerNode);
101  void HandleReadServer (Ptr<Socket> socket);
102 
103  // client part
104  void StartClient (Ptr<Node> ClientNode);
105  void HandleReadClient (Ptr<Socket> socket);
106  void HandleReadIcmpClient (Ipv4Address icmpSource, uint8_t icmpTtl, uint8_t icmpType,
107  uint8_t icmpCode,uint32_t icmpInfo);
108 
109  void SetFill (uint8_t *fill, uint32_t fillSize, uint32_t dataSize);
110  Ptr<Packet> SendClient (void);
111 
112 };
113 
114 
115 Ipv4FragmentationTest::Ipv4FragmentationTest ()
116  : TestCase ("Verify the IPv4 layer 3 protocol fragmentation and reassembly")
117 {
118  m_socketServer = 0;
119  m_data = 0;
120  m_dataSize = 0;
121 }
122 
123 Ipv4FragmentationTest::~Ipv4FragmentationTest ()
124 {
125  if ( m_data )
126  {
127  delete[] m_data;
128  }
129  m_data = 0;
130  m_dataSize = 0;
131 }
132 
133 
134 void
135 Ipv4FragmentationTest::StartServer (Ptr<Node> ServerNode)
136 {
137 
138  if (m_socketServer == 0)
139  {
140  TypeId tid = TypeId::LookupByName ("ns3::UdpSocketFactory");
141  m_socketServer = Socket::CreateSocket (ServerNode, tid);
142  InetSocketAddress local = InetSocketAddress (Ipv4Address::GetAny (), 9);
143  m_socketServer->Bind (local);
144  Ptr<UdpSocket> udpSocket = DynamicCast<UdpSocket> (m_socketServer);
145  if (udpSocket)
146  {
147  // equivalent to setsockopt (MCAST_JOIN_GROUP)
148  udpSocket->MulticastJoinGroup (0, Ipv4Address ("10.0.0.1"));
149  }
150  }
151 
152  m_socketServer->SetRecvCallback(MakeCallback(&Ipv4FragmentationTest::HandleReadServer, this));
153 }
154 
155 void
156 Ipv4FragmentationTest::HandleReadServer (Ptr<Socket> socket)
157 {
158  Ptr<Packet> packet;
159  Address from;
160  while ((packet = socket->RecvFrom (from)))
161  {
162  if (InetSocketAddress::IsMatchingType (from))
163  {
164  packet->RemoveAllPacketTags ();
165  packet->RemoveAllByteTags ();
166 
167  m_receivedPacketServer = packet->Copy();
168  }
169  }
170 }
171 
172 void
173 Ipv4FragmentationTest::StartClient (Ptr<Node> ClientNode)
174 {
175 
176  if (m_socketClient == 0)
177  {
178  TypeId tid = TypeId::LookupByName ("ns3::UdpSocketFactory");
179  m_socketClient = Socket::CreateSocket (ClientNode, tid);
180  m_socketClient->Bind ();
181  m_socketClient->Connect (InetSocketAddress (Ipv4Address ("10.0.0.1"), 9));
182  CallbackValue cbValue = MakeCallback(&Ipv4FragmentationTest::HandleReadIcmpClient, this);
183  m_socketClient->SetAttribute ("IcmpCallback", cbValue);
184  }
185 
186  m_socketClient->SetRecvCallback(MakeCallback(&Ipv4FragmentationTest::HandleReadClient, this));
187 }
188 
189 void
190 Ipv4FragmentationTest::HandleReadClient (Ptr<Socket> socket)
191 {
192  Ptr<Packet> packet;
193  Address from;
194  while ((packet = socket->RecvFrom (from)))
195  {
196  if (InetSocketAddress::IsMatchingType (from))
197  {
198  m_receivedPacketClient = packet->Copy();
199  }
200  }
201 }
202 
203 void
204 Ipv4FragmentationTest::HandleReadIcmpClient (Ipv4Address icmpSource,
205  uint8_t icmpTtl, uint8_t icmpType,
206  uint8_t icmpCode, uint32_t icmpInfo)
207 {
208  m_icmpType = icmpType;
209 }
210 
211 void
212 Ipv4FragmentationTest::SetFill (uint8_t *fill, uint32_t fillSize, uint32_t dataSize)
213 {
214  if (dataSize != m_dataSize)
215  {
216  delete [] m_data;
217  m_data = new uint8_t [dataSize];
218  m_dataSize = dataSize;
219  }
220 
221  if (fillSize >= dataSize)
222  {
223  memcpy (m_data, fill, dataSize);
224  return;
225  }
226 
227  uint32_t filled = 0;
228  while (filled + fillSize < dataSize)
229  {
230  memcpy (&m_data[filled], fill, fillSize);
231  filled += fillSize;
232  }
233 
234  memcpy(&m_data[filled], fill, dataSize - filled);
235 
236  m_size = dataSize;
237 }
238 
239 Ptr<Packet> Ipv4FragmentationTest::SendClient (void)
240 {
241  Ptr<Packet> p;
242  if (m_dataSize)
243  {
244  p = Create<Packet> (m_data, m_dataSize);
245  }
246  else
247  {
248  p = Create<Packet> (m_size);
249  }
250  m_socketClient->Send (p);
251 
252  return p;
253 }
254 
255 void
257 {
258  // set the arp cache to something quite high
259  // we shouldn't need because the NetDevice used doesn't need arp, but still
260  Config::SetDefault ("ns3::ArpCache::PendingQueueSize", UintegerValue (100));
261 
262  // Create topology
263 
264  // Receiver Node
265  Ptr<Node> serverNode = CreateObject<Node> ();
266  AddInternetStack (serverNode);
267  Ptr<ErrorNetDevice> serverDev;
268  Ptr<BinaryErrorModel> serverDevErrorModel = CreateObject<BinaryErrorModel> ();
269  {
270  serverDev = CreateObject<ErrorNetDevice> ();
271  serverDev->SetAddress (Mac48Address::ConvertFrom (Mac48Address::Allocate ()));
272  serverDev->SetMtu(1500);
273  serverDev->SetReceiveErrorModel(serverDevErrorModel);
274  serverDevErrorModel->Disable();
275  serverNode->AddDevice (serverDev);
276  Ptr<Ipv4> ipv4 = serverNode->GetObject<Ipv4> ();
277  uint32_t netdev_idx = ipv4->AddInterface (serverDev);
278  Ipv4InterfaceAddress ipv4Addr = Ipv4InterfaceAddress (Ipv4Address ("10.0.0.1"), Ipv4Mask (0xffff0000U));
279  ipv4->AddAddress (netdev_idx, ipv4Addr);
280  ipv4->SetUp (netdev_idx);
281  }
282  StartServer(serverNode);
283 
284  // Sender Node
285  Ptr<Node> clientNode = CreateObject<Node> ();
286  AddInternetStack (clientNode);
287  Ptr<ErrorNetDevice> clientDev;
288  Ptr<BinaryErrorModel> clientDevErrorModel = CreateObject<BinaryErrorModel> ();
289  {
290  clientDev = CreateObject<ErrorNetDevice> ();
291  clientDev->SetAddress (Mac48Address::ConvertFrom (Mac48Address::Allocate ()));
292  clientDev->SetMtu(1000);
293  clientDev->SetReceiveErrorModel(clientDevErrorModel);
294  clientDevErrorModel->Disable();
295  clientNode->AddDevice (clientDev);
296  Ptr<Ipv4> ipv4 = clientNode->GetObject<Ipv4> ();
297  uint32_t netdev_idx = ipv4->AddInterface (clientDev);
298  Ipv4InterfaceAddress ipv4Addr = Ipv4InterfaceAddress (Ipv4Address ("10.0.0.2"), Ipv4Mask (0xffff0000U));
299  ipv4->AddAddress (netdev_idx, ipv4Addr);
300  ipv4->SetUp (netdev_idx);
301  }
302  StartClient(clientNode);
303 
304  // link the two nodes
305  Ptr<ErrorChannel> channel = CreateObject<ErrorChannel> ();
306  serverDev->SetChannel (channel);
307  clientDev->SetChannel (channel);
308  channel->SetJumpingTime(Seconds(0.5));
309 
310 
311  // some small packets, some rather big ones
312  uint32_t packetSizes[5] = {1000, 2000, 5000, 10000, 65000};
313 
314  // using the alphabet
315  uint8_t fillData[78];
316  for ( uint32_t k=48; k<=125; k++ )
317  {
318  fillData[k-48] = k;
319  }
320 
321  // First test: normal channel, no errors, no delays
322  for( int i= 0; i<5; i++)
323  {
324  uint32_t packetSize = packetSizes[i];
325 
326  SetFill (fillData, 78, packetSize);
327 
328  m_receivedPacketServer = Create<Packet> ();
329  Simulator::ScheduleWithContext (m_socketClient->GetNode ()->GetId (), Seconds (0),
330  &Ipv4FragmentationTest::SendClient, this);
331  Simulator::Run ();
332 
333  uint8_t recvBuffer[65000];
334 
335  uint16_t recvSize = m_receivedPacketServer->GetSize ();
336 
337  NS_TEST_EXPECT_MSG_EQ (recvSize, packetSizes[i], "Packet size not correct");
338 
339  m_receivedPacketServer->CopyData(recvBuffer, 65000);
340  NS_TEST_EXPECT_MSG_EQ (memcmp(m_data, recvBuffer, m_receivedPacketServer->GetSize ()),
341  0, "Packet content differs");
342  }
343 
344  // Second test: normal channel, no errors, delays each 2 packets.
345  // Each other fragment will arrive out-of-order.
346  // The packets should be received correctly since reassembly will reorder the fragments.
347  channel->SetJumpingMode(true);
348  for( int i= 0; i<5; i++)
349  {
350  uint32_t packetSize = packetSizes[i];
351 
352  SetFill (fillData, 78, packetSize);
353 
354  m_receivedPacketServer = Create<Packet> ();
355  Simulator::ScheduleWithContext (m_socketClient->GetNode ()->GetId (), Seconds (0),
356  &Ipv4FragmentationTest::SendClient, this);
357  Simulator::Run ();
358 
359  uint8_t recvBuffer[65000];
360 
361  uint16_t recvSize = m_receivedPacketServer->GetSize ();
362 
363  NS_TEST_EXPECT_MSG_EQ (recvSize, packetSizes[i], "Packet size not correct");
364 
365  m_receivedPacketServer->CopyData(recvBuffer, 65000);
366  NS_TEST_EXPECT_MSG_EQ (memcmp(m_data, recvBuffer, m_receivedPacketServer->GetSize ()),
367  0, "Packet content differs");
368  }
369  channel->SetJumpingMode(false);
370 
371  // Third test: normal channel, some errors, no delays.
372  // The reassembly procedure should fire a timeout after 30 seconds (as specified in the RFCs).
373  // Upon the timeout, the fragments received so far are discarded and an ICMP should be sent back
374  // to the sender (if the first fragment has been received).
375  // In this test case the first fragment is received, so we do expect an ICMP.
376  // Client -> Server : errors enabled
377  // Server -> Client : errors disabled (we want to have back the ICMP)
378  clientDevErrorModel->Disable();
379  serverDevErrorModel->Enable();
380  for( int i= 1; i<5; i++)
381  {
382  uint32_t packetSize = packetSizes[i];
383 
384  SetFill (fillData, 78, packetSize);
385 
386  // reset the model, we want to receive the very first fragment.
387  serverDevErrorModel->Reset();
388 
389  m_receivedPacketServer = Create<Packet> ();
390  m_icmpType = 0;
391  Simulator::ScheduleWithContext (m_socketClient->GetNode ()->GetId (), Seconds (0),
392  &Ipv4FragmentationTest::SendClient, this);
393  Simulator::Run ();
394 
395  uint16_t recvSize = m_receivedPacketServer->GetSize ();
396 
397  NS_TEST_EXPECT_MSG_EQ ((recvSize == 0), true, "Server got a packet, something wrong");
398  NS_TEST_EXPECT_MSG_EQ ((m_icmpType == 11), true, "Client did not receive ICMP::TIME_EXCEEDED");
399  }
400 
401 
402  Simulator::Destroy ();
403 }
404 //-----------------------------------------------------------------------------
406 {
407 public:
408  Ipv4FragmentationTestSuite () : TestSuite ("ipv4-fragmentation", UNIT)
409  {
410  AddTestCase (new Ipv4FragmentationTest, TestCase::QUICK);
411  }
412 } g_ipv4fragmentationTestSuite;
virtual uint32_t AddInterface(Ptr< NetDevice > device)=0
an Inet address class
a class to represent an Ipv4 address mask
Definition: ipv4-address.h:210
A suite of tests to run.
Definition: test.h:962
uint32_t GetSize(void) const
Definition: packet.h:620
virtual bool SetMtu(const uint16_t mtu)
encapsulates test code
Definition: test.h:834
TestSuite(std::string name, Type type=UNIT)
Constuct a new test suite.
Definition: test.cc:354
A sockets interface to UDP.
a polymophic address class
Definition: address.h:86
void RemoveAllPacketTags(void)
Definition: packet.cc:888
virtual int MulticastJoinGroup(uint32_t interface, const Address &groupAddress)=0
Corresponds to socket option MCAST_JOIN_GROUP.
virtual void SetUp(uint32_t interface)=0
Hold an unsigned integer type.
Definition: uinteger.h:46
Callback< R > MakeCallback(R(T::*memPtr)(void), OBJ objPtr)
Definition: callback.h:502
void SetRecvCallback(Callback< void, Ptr< Socket > >)
Notify application when new data is available to be read.
Definition: socket.cc:127
void Disable(void)
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:75
Ptr< Packet > Copy(void) const
Definition: packet.cc:131
virtual int Bind(const Address &address)=0
Allocate a local endpoint for this socket.
void SetReceiveErrorModel(Ptr< ErrorModel > em)
virtual void SetAddress(Address address)
void AddTestCase(TestCase *testCase) NS_DEPRECATED
Add an individual test case to this test suite.
Definition: test.cc:172
Ipv4 addresses are stored in host order in this class.
Definition: ipv4-address.h:38
Time Seconds(double seconds)
create ns3::Time instances in units of seconds.
Definition: nstime.h:586
uint32_t AddDevice(Ptr< NetDevice > device)
Definition: node.cc:119
uint32_t GetId(void) const
Definition: node.cc:105
a class to store IPv4 address information on an interface
virtual Ptr< Node > GetNode(void) const =0
void RemoveAllByteTags(void)
Definition: packet.cc:378
virtual bool AddAddress(uint32_t interface, Ipv4InterfaceAddress address)=0
uint32_t CopyData(uint8_t *buffer, uint32_t size) const
Definition: packet.cc:398
virtual void DoRun(void)
Implementation to actually run this test case.
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.
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)
Definition: object-base.cc:160
Ptr< T > GetObject(void) const
Definition: object.h:332
a unique identifier for an interface.
Definition: type-id.h:44
void Enable(void)
Definition: error-model.cc:124
void SetRoutingProtocol(Ptr< Ipv4RoutingProtocol > routingProtocol)
Register a new routing protocol to be used by this Ipv4 stack.