A Discrete-Event Network Simulator
API
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
ipv6-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  */
23 #define NS3_LOG_ENABLE 1
24 
25 #include "ns3/test.h"
26 #include "ns3/config.h"
27 #include "ns3/uinteger.h"
28 #include "ns3/socket-factory.h"
29 #include "ns3/ipv4-raw-socket-factory.h"
30 #include "ns3/ipv6-raw-socket-factory.h"
31 #include "ns3/udp-socket-factory.h"
32 #include "ns3/simulator.h"
33 #include "error-channel.h"
34 #include "error-net-device.h"
35 #include "ns3/drop-tail-queue.h"
36 #include "ns3/socket.h"
37 #include "ns3/udp-socket.h"
38 
39 #include "ns3/log.h"
40 #include "ns3/node.h"
41 #include "ns3/inet-socket-address.h"
42 #include "ns3/boolean.h"
43 
44 #include "ns3/ipv6-static-routing.h"
45 #include "ns3/ipv6-list-routing.h"
46 #include "ns3/inet6-socket-address.h"
47 #
48 #include "ns3/arp-l3-protocol.h"
49 #include "ns3/ipv4-l3-protocol.h"
50 #include "ns3/icmpv4-l4-protocol.h"
51 #include "ns3/ipv4-list-routing.h"
52 #include "ns3/ipv4-static-routing.h"
53 #include "ns3/udp-l4-protocol.h"
54 
55 #include "ns3/ipv6-l3-protocol.h"
56 #include "ns3/icmpv6-l4-protocol.h"
57 
58 #include <string>
59 #include <limits>
60 #include <netinet/in.h>
61 
62 using namespace ns3;
63 
64 class UdpSocketImpl;
65 
66 static void
68 {
69  //IPV6
70  Ptr<Ipv6L3Protocol> ipv6 = CreateObject<Ipv6L3Protocol> ();
71 
72  //Routing for Ipv6
73  Ptr<Ipv6ListRouting> ipv6Routing = CreateObject<Ipv6ListRouting> ();
74  ipv6->SetRoutingProtocol (ipv6Routing);
75  Ptr<Ipv6StaticRouting> ipv6staticRouting = CreateObject<Ipv6StaticRouting> ();
76  ipv6Routing->AddRoutingProtocol (ipv6staticRouting, 0);
77  node->AggregateObject (ipv6);
78 
79  //ICMPv6
80  Ptr<Icmpv6L4Protocol> icmp6 = CreateObject<Icmpv6L4Protocol> ();
81  node->AggregateObject (icmp6);
82 
83  //Ipv6 Extensions
84  ipv6->RegisterExtensions ();
85  ipv6->RegisterOptions ();
86 
87  //UDP
88  Ptr<UdpL4Protocol> udp = CreateObject<UdpL4Protocol> ();
89  node->AggregateObject (udp);
90 }
91 
92 
94 {
98 
99 
102  uint32_t m_dataSize;
103  uint8_t *m_data;
104  uint32_t m_size;
105  uint8_t m_icmpType;
106  uint8_t m_icmpCode;
107 
108 public:
109  virtual void DoRun (void);
112 
113  // server part
114  void StartServer (Ptr<Node> ServerNode);
115  void HandleReadServer (Ptr<Socket> socket);
116 
117  // client part
118  void StartClient (Ptr<Node> ClientNode);
119  void HandleReadClient (Ptr<Socket> socket);
120  void HandleReadIcmpClient (Ipv6Address icmpSource, uint8_t icmpTtl, uint8_t icmpType,
121  uint8_t icmpCode,uint32_t icmpInfo);
122 
123  void SetFill (uint8_t *fill, uint32_t fillSize, uint32_t dataSize);
124  Ptr<Packet> SendClient (void);
125 
126 };
127 
128 
130  : TestCase ("Verify the IPv6 layer 3 protocol fragmentation and reassembly")
131 {
132  m_socketServer = 0;
133  m_data = 0;
134  m_dataSize = 0;
135 }
136 
138 {
139  if ( m_data )
140  {
141  delete[] m_data;
142  }
143  m_data = 0;
144  m_dataSize = 0;
145 }
146 
147 
148 void
150 {
151 
152  if (m_socketServer == 0)
153  {
154  TypeId tid = TypeId::LookupByName ("ns3::UdpSocketFactory");
155  m_socketServer = Socket::CreateSocket (ServerNode, tid);
156  Inet6SocketAddress local = Inet6SocketAddress (Ipv6Address ("2001::1"), 9);
157  m_socketServer->Bind (local);
158  Ptr<UdpSocket> udpSocket = DynamicCast<UdpSocket> (m_socketServer);
159  }
160 
162 }
163 
164 void
166 {
167  Ptr<Packet> packet;
168  Address from;
169  while ((packet = socket->RecvFrom (from)))
170  {
171  if (Inet6SocketAddress::IsMatchingType (from))
172  {
173  packet->RemoveAllPacketTags ();
174  packet->RemoveAllByteTags ();
175 
176  m_receivedPacketServer = packet->Copy ();
177  }
178  }
179 }
180 
181 void
183 {
184 
185  if (m_socketClient == 0)
186  {
187  TypeId tid = TypeId::LookupByName ("ns3::UdpSocketFactory");
188  m_socketClient = Socket::CreateSocket (ClientNode, tid);
189  m_socketClient->Bind (Inet6SocketAddress (Ipv6Address::GetAny (), 9));
192  m_socketClient->SetAttribute ("IcmpCallback6", cbValue);
193  }
194 
196 }
197 
198 void
200 {
201  Ptr<Packet> packet;
202  Address from;
203  while ((packet = socket->RecvFrom (from)))
204  {
205  if (Inet6SocketAddress::IsMatchingType (from))
206  {
207  m_receivedPacketClient = packet->Copy ();
208  }
209  }
210 }
211 
212 void
214  uint8_t icmpTtl, uint8_t icmpType,
215  uint8_t icmpCode, uint32_t icmpInfo)
216 {
217  m_icmpType = icmpType;
218  m_icmpCode = icmpCode;
219 }
220 
221 void
222 Ipv6FragmentationTest::SetFill (uint8_t *fill, uint32_t fillSize, uint32_t dataSize)
223 {
224  if (dataSize != m_dataSize)
225  {
226  delete [] m_data;
227  m_data = new uint8_t [dataSize];
228  m_dataSize = dataSize;
229  }
230 
231  if (fillSize >= dataSize)
232  {
233  memcpy (m_data, fill, dataSize);
234  return;
235  }
236 
237  uint32_t filled = 0;
238  while (filled + fillSize < dataSize)
239  {
240  memcpy (&m_data[filled], fill, fillSize);
241  filled += fillSize;
242  }
243 
244  memcpy (&m_data[filled], fill, dataSize - filled);
245 
246  m_size = dataSize;
247 }
248 
250 {
251  Ptr<Packet> p;
252  if (m_dataSize)
253  {
254  p = Create<Packet> (m_data, m_dataSize);
255  }
256  else
257  {
258  p = Create<Packet> (m_size);
259  }
260  m_socketClient->Send (p);
261 
262  return p;
263 }
264 
265 void
267 {
268  // set the arp cache to something quite high
269  // we shouldn't need because the NetDevice used doesn't need arp, but still
270  // Config::SetDefault ("ns3::ArpCache::PendingQueueSize", UintegerValue (100));
271 // LogComponentEnable ("ErrorNetDevice", LOG_LEVEL_ALL);
272 // LogComponentEnableAll(LOG_LEVEL_ALL);
273 // Create topology
274 
275  // Receiver Node
276  Ptr<Node> serverNode = CreateObject<Node> ();
277  AddInternetStack (serverNode);
278  Ptr<ErrorNetDevice> serverDev;
279  Ptr<BinaryErrorModel> serverDevErrorModel = CreateObject<BinaryErrorModel> ();
280  {
281  serverDev = CreateObject<ErrorNetDevice> ();
282  serverDev->SetAddress (Mac48Address::ConvertFrom (Mac48Address::Allocate ()));
283  serverDev->SetMtu (1500);
284  serverDev->SetReceiveErrorModel (serverDevErrorModel);
285  serverDevErrorModel->Disable ();
286  serverNode->AddDevice (serverDev);
287  Ptr<Ipv6> ipv6 = serverNode->GetObject<Ipv6> ();
288  uint32_t netdev_idx = ipv6->AddInterface (serverDev);
289  Ipv6InterfaceAddress ipv6Addr = Ipv6InterfaceAddress (Ipv6Address ("2001::1"), Ipv6Prefix (32));
290  ipv6->AddAddress (netdev_idx, ipv6Addr);
291  ipv6->SetUp (netdev_idx);
292  }
293  StartServer (serverNode);
294 
295  // Sender Node
296  Ptr<Node> clientNode = CreateObject<Node> ();
297  AddInternetStack (clientNode);
298  Ptr<ErrorNetDevice> clientDev;
299  Ptr<BinaryErrorModel> clientDevErrorModel = CreateObject<BinaryErrorModel> ();
300  {
301  clientDev = CreateObject<ErrorNetDevice> ();
302  clientDev->SetAddress (Mac48Address::ConvertFrom (Mac48Address::Allocate ()));
303  clientDev->SetMtu (1000);
304  clientDev->SetReceiveErrorModel (clientDevErrorModel);
305  clientDevErrorModel->Disable ();
306  clientNode->AddDevice (clientDev);
307  Ptr<Ipv6> ipv6 = clientNode->GetObject<Ipv6> ();
308  uint32_t netdev_idx = ipv6->AddInterface (clientDev);
309  Ipv6InterfaceAddress ipv6Addr = Ipv6InterfaceAddress (Ipv6Address ("2001::2"), Ipv6Prefix (32));
310  ipv6->AddAddress (netdev_idx, ipv6Addr);
311  ipv6->SetUp (netdev_idx);
312  }
313  StartClient (clientNode);
314 
315  // link the two nodes
316  Ptr<ErrorChannel> channel = CreateObject<ErrorChannel> ();
317  serverDev->SetChannel (channel);
318  clientDev->SetChannel (channel);
319  channel->SetJumpingTime (Seconds (0.5));
320 
321 
322  // some small packets, some rather big ones
323  uint32_t packetSizes[5] = {1000, 2000, 5000, 10000, 65000};
324 
325  // using the alphabet
326  uint8_t fillData[78];
327  for ( uint32_t k = 48; k <= 125; k++ )
328  {
329  fillData[k - 48] = k;
330  }
331 
332  // First test: normal channel, no errors, no delays
333  for ( int i = 0; i < 5; i++)
334  {
335  uint32_t packetSize = packetSizes[i];
336 
337  SetFill (fillData, 78, packetSize);
338 
339  m_receivedPacketServer = Create<Packet> ();
340  Simulator::ScheduleWithContext (m_socketClient->GetNode ()->GetId (), Seconds (0),
342  Simulator::Run ();
343 
344  uint8_t recvBuffer[65000];
345 
346  uint16_t recvSize = m_receivedPacketServer->GetSize ();
347 
348  NS_TEST_EXPECT_MSG_EQ (recvSize, packetSizes[i],
349  "Packet size not correct: recvSize: " << recvSize << " packetSizes[" << i << "]: " << packetSizes[i] );
350 
351  m_receivedPacketServer->CopyData (recvBuffer, 65000);
352  NS_TEST_EXPECT_MSG_EQ (memcmp (m_data, recvBuffer, m_receivedPacketServer->GetSize ()),
353  0, "Packet content differs");
354  }
355 
356  // Second test: normal channel, no errors, delays each 2 packets.
357  // Each other fragment will arrive out-of-order.
358  // The packets should be received correctly since reassembly will reorder the fragments.
359  channel->SetJumpingMode (true);
360  for ( int i = 0; i < 5; i++)
361  {
362  uint32_t packetSize = packetSizes[i];
363 
364  SetFill (fillData, 78, packetSize);
365 
366  m_receivedPacketServer = Create<Packet> ();
367  Simulator::ScheduleWithContext (m_socketClient->GetNode ()->GetId (), Seconds (0),
369  Simulator::Run ();
370 
371  uint8_t recvBuffer[65000];
372 
373  uint16_t recvSize = m_receivedPacketServer->GetSize ();
374 
375  NS_TEST_EXPECT_MSG_EQ (recvSize, packetSizes[i],
376  "Packet size not correct: recvSize: " << recvSize << " packetSizes[" << i << "]: " << packetSizes[i] );
377 
378  m_receivedPacketServer->CopyData (recvBuffer, 65000);
379  NS_TEST_EXPECT_MSG_EQ (memcmp (m_data, recvBuffer, m_receivedPacketServer->GetSize ()),
380  0, "Packet content differs");
381  }
382  channel->SetJumpingMode (false);
383 
384  // Third test: normal channel, some errors, no delays.
385  // The reassembly procedure should fire a timeout after 30 seconds (as specified in the RFCs).
386  // Upon the timeout, the fragments received so far are discarded and an ICMP should be sent back
387  // to the sender (if the first fragment has been received).
388  // In this test case the first fragment is received, so we do expect an ICMP.
389  // Client -> Server : errors enabled
390  // Server -> Client : errors disabled (we want to have back the ICMP)
391  clientDevErrorModel->Disable ();
392  serverDevErrorModel->Enable ();
393  for ( int i = 1; i < 5; i++)
394  {
395  uint32_t packetSize = packetSizes[i];
396 
397  SetFill (fillData, 78, packetSize);
398 
399  // reset the model, we want to receive the very first fragment.
400  serverDevErrorModel->Reset ();
401 
402  m_receivedPacketServer = Create<Packet> ();
403  m_icmpType = 0;
404  m_icmpCode = 0;
405  Simulator::ScheduleWithContext (m_socketClient->GetNode ()->GetId (), Seconds (0),
407  Simulator::Run ();
408 
409  uint16_t recvSize = m_receivedPacketServer->GetSize ();
410 
411  NS_TEST_EXPECT_MSG_EQ ((recvSize == 0), true, "Server got a packet, something wrong");
412  NS_TEST_EXPECT_MSG_EQ ((m_icmpType == Icmpv6Header::ICMPV6_ERROR_TIME_EXCEEDED)
413  && (m_icmpCode == Icmpv6Header::ICMPV6_FRAGTIME),
414  true, "Client did not receive ICMPv6::TIME_EXCEEDED " << int(m_icmpType) << int(m_icmpCode) );
415  }
416 
417 
418  Simulator::Destroy ();
419 }
420 //-----------------------------------------------------------------------------
422 {
423 public:
424  Ipv6FragmentationTestSuite () : TestSuite ("ipv6-fragmentation", UNIT)
425  {
427  }