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 "ns3/simple-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  // Create topology
269 
270  // Receiver Node
271  Ptr<Node> serverNode = CreateObject<Node> ();
272  AddInternetStack (serverNode);
273  Ptr<SimpleNetDevice> serverDev;
274  Ptr<BinaryErrorModel> serverDevErrorModel = CreateObject<BinaryErrorModel> ();
275  {
276  serverDev = CreateObject<SimpleNetDevice> ();
277  serverDev->SetAddress (Mac48Address::ConvertFrom (Mac48Address::Allocate ()));
278  serverDev->SetMtu (1500);
279  serverDev->SetReceiveErrorModel (serverDevErrorModel);
280  serverDevErrorModel->Disable ();
281  serverNode->AddDevice (serverDev);
282  Ptr<Ipv6> ipv6 = serverNode->GetObject<Ipv6> ();
283  uint32_t netdev_idx = ipv6->AddInterface (serverDev);
284  Ipv6InterfaceAddress ipv6Addr = Ipv6InterfaceAddress (Ipv6Address ("2001::1"), Ipv6Prefix (32));
285  ipv6->AddAddress (netdev_idx, ipv6Addr);
286  ipv6->SetUp (netdev_idx);
287  }
288  StartServer (serverNode);
289 
290  // Sender Node
291  Ptr<Node> clientNode = CreateObject<Node> ();
292  AddInternetStack (clientNode);
293  Ptr<SimpleNetDevice> clientDev;
294  Ptr<BinaryErrorModel> clientDevErrorModel = CreateObject<BinaryErrorModel> ();
295  {
296  clientDev = CreateObject<SimpleNetDevice> ();
297  clientDev->SetAddress (Mac48Address::ConvertFrom (Mac48Address::Allocate ()));
298  clientDev->SetMtu (1500);
299  clientDev->SetReceiveErrorModel (clientDevErrorModel);
300  clientDevErrorModel->Disable ();
301  clientNode->AddDevice (clientDev);
302  Ptr<Ipv6> ipv6 = clientNode->GetObject<Ipv6> ();
303  uint32_t netdev_idx = ipv6->AddInterface (clientDev);
304  Ipv6InterfaceAddress ipv6Addr = Ipv6InterfaceAddress (Ipv6Address ("2001::2"), Ipv6Prefix (32));
305  ipv6->AddAddress (netdev_idx, ipv6Addr);
306  ipv6->SetUp (netdev_idx);
307  }
308  StartClient (clientNode);
309 
310  // link the two nodes
311  Ptr<ErrorChannel> channel = CreateObject<ErrorChannel> ();
312  serverDev->SetChannel (channel);
313  clientDev->SetChannel (channel);
314  channel->SetJumpingTime (Seconds (0.5));
315 
316 
317  // some small packets, some rather big ones
318  uint32_t packetSizes[5] = {2000, 2500, 5000, 10000, 65000};
319 
320  // using the alphabet
321  uint8_t fillData[78];
322  for ( uint32_t k = 48; k <= 125; k++ )
323  {
324  fillData[k - 48] = k;
325  }
326 
327  // First test: normal channel, no errors, no delays
328  for ( int i = 0; i < 5; i++)
329  {
330  uint32_t packetSize = packetSizes[i];
331 
332  SetFill (fillData, 78, packetSize);
333 
334  m_receivedPacketServer = Create<Packet> ();
335  Simulator::ScheduleWithContext (m_socketClient->GetNode ()->GetId (), Seconds (0),
337  Simulator::Run ();
338 
339  uint8_t recvBuffer[65000];
340 
341  uint16_t recvSize = m_receivedPacketServer->GetSize ();
342 
343  NS_TEST_EXPECT_MSG_EQ (recvSize, packetSizes[i],
344  "Packet size not correct: recvSize: " << recvSize << " packetSizes[" << i << "]: " << packetSizes[i] );
345 
346  m_receivedPacketServer->CopyData (recvBuffer, 65000);
347  NS_TEST_EXPECT_MSG_EQ (memcmp (m_data, recvBuffer, m_receivedPacketServer->GetSize ()),
348  0, "Packet content differs");
349  }
350 
351  // Second test: normal channel, no errors, delays each 2 packets.
352  // Each other fragment will arrive out-of-order.
353  // The packets should be received correctly since reassembly will reorder the fragments.
354  channel->SetJumpingMode (true);
355  for ( int i = 0; i < 5; i++)
356  {
357  uint32_t packetSize = packetSizes[i];
358 
359  SetFill (fillData, 78, packetSize);
360 
361  m_receivedPacketServer = Create<Packet> ();
362  Simulator::ScheduleWithContext (m_socketClient->GetNode ()->GetId (), Seconds (0),
364  Simulator::Run ();
365 
366  uint8_t recvBuffer[65000];
367 
368  uint16_t recvSize = m_receivedPacketServer->GetSize ();
369 
370  NS_TEST_EXPECT_MSG_EQ (recvSize, packetSizes[i],
371  "Packet size not correct: recvSize: " << recvSize << " packetSizes[" << i << "]: " << packetSizes[i] );
372 
373  m_receivedPacketServer->CopyData (recvBuffer, 65000);
374  NS_TEST_EXPECT_MSG_EQ (memcmp (m_data, recvBuffer, m_receivedPacketServer->GetSize ()),
375  0, "Packet content differs");
376  }
377  channel->SetJumpingMode (false);
378 
379  // Third test: normal channel, some errors, no delays.
380  // The reassembly procedure should fire a timeout after 30 seconds (as specified in the RFCs).
381  // Upon the timeout, the fragments received so far are discarded and an ICMP should be sent back
382  // to the sender (if the first fragment has been received).
383  // In this test case the first fragment is received, so we do expect an ICMP.
384  // Client -> Server : errors enabled
385  // Server -> Client : errors disabled (we want to have back the ICMP)
386  clientDevErrorModel->Disable ();
387  serverDevErrorModel->Enable ();
388  for ( int i = 1; i < 5; i++)
389  {
390  uint32_t packetSize = packetSizes[i];
391 
392  SetFill (fillData, 78, packetSize);
393 
394  // reset the model, we want to receive the very first fragment.
395  serverDevErrorModel->Reset ();
396 
397  m_receivedPacketServer = Create<Packet> ();
398  m_icmpType = 0;
399  m_icmpCode = 0;
400  Simulator::ScheduleWithContext (m_socketClient->GetNode ()->GetId (), Seconds (0),
402  Simulator::Run ();
403 
404  uint16_t recvSize = m_receivedPacketServer->GetSize ();
405 
406  NS_TEST_EXPECT_MSG_EQ ((recvSize == 0), true, "Server got a packet, something wrong");
407  NS_TEST_EXPECT_MSG_EQ ((m_icmpType == Icmpv6Header::ICMPV6_ERROR_TIME_EXCEEDED)
408  && (m_icmpCode == Icmpv6Header::ICMPV6_FRAGTIME),
409  true, "Client did not receive ICMPv6::TIME_EXCEEDED " << int(m_icmpType) << int(m_icmpCode) );
410  }
411 
412 
413  Simulator::Destroy ();
414 }
415 //-----------------------------------------------------------------------------
417 {
418 public:
419  Ipv6FragmentationTestSuite () : TestSuite ("ipv6-fragmentation", UNIT)
420  {
421  AddTestCase (new Ipv6FragmentationTest, TestCase::QUICK);
422  }
Access to the IPv6 forwarding table, interfaces, and configuration.
Definition: ipv6.h:79
A suite of tests to run.
Definition: test.h:1025
IPv6 address associated with an interface.
uint32_t GetSize(void) const
Definition: packet.h:650
encapsulates test code
Definition: test.h:849
void StartServer(Ptr< Node > ServerNode)
A sockets interface to UDP.
a polymophic address class
Definition: address.h:86
AttributeValue form of a Callback.
Definition: callback.h:1658
void RemoveAllPacketTags(void)
Remove all packet tags.
Definition: packet.cc:869
void HandleReadIcmpClient(Ipv6Address icmpSource, uint8_t icmpTtl, uint8_t icmpType, uint8_t icmpCode, uint32_t icmpInfo)
virtual bool SetMtu(const uint16_t mtu)
#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:244
An Inet6 address class.
Callback< R > MakeCallback(R(T::*memPtr)(void), OBJ objPtr)
Definition: callback.h:1238
void HandleReadClient(Ptr< Socket > socket)
void SetRecvCallback(Callback< void, Ptr< Socket > >)
Notify application when new data is available to be read.
Definition: socket.cc:128
void Disable(void)
Disable the error model.
Definition: error-model.cc:132
void AggregateObject(Ptr< Object > other)
Definition: object.cc:243
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)
Ptr< Packet > Copy(void) const
Definition: packet.cc:122
virtual int Bind(const Address &address)=0
Allocate a local endpoint for this socket.
void SetReceiveErrorModel(Ptr< ErrorModel > em)
Attach a receive ErrorModel to the SimpleNetDevice.
void AddTestCase(TestCase *testCase) NS_DEPRECATED
Add an individual child TestCase case to this TestCase.
Definition: test.cc:173
void HandleReadServer(Ptr< Socket > socket)
Ptr< Packet > SendClient(void)
virtual uint32_t AddInterface(Ptr< NetDevice > device)=0
Add a NetDevice interface.
virtual void DoRun(void)
Implementation to actually run this TestCase.
virtual void RegisterExtensions()
Register the IPv6 Extensions.
Describes an IPv6 address.
Definition: ipv6-address.h:46
void SetRoutingProtocol(Ptr< Ipv6RoutingProtocol > routingProtocol)
Set routing protocol for this stack.
uint32_t AddDevice(Ptr< NetDevice > device)
Definition: node.cc:118
uint32_t GetId(void) const
Definition: node.cc:104
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.
void RemoveAllByteTags(void)
Remove all byte tags stored in this packet.
Definition: packet.cc:361
void SetFill(uint8_t *fill, uint32_t fillSize, uint32_t dataSize)
virtual void RegisterOptions()
Register the IPv6 Options.
Describes an IPv6 prefix.
Definition: ipv6-address.h:387
virtual bool AddAddress(uint32_t interface, Ipv6InterfaceAddress address)=0
Add an address on the specified IPv6 interface.
uint32_t CopyData(uint8_t *buffer, uint32_t size) const
Copy the packet contents to a byte buffer.
Definition: packet.cc:381
void SetJumpingTime(Time delay)
Set the delay for the odd packets (even ones are not delayed)
void StartClient(Ptr< Node > ClientNode)
Ipv6FragmentationTestSuite g_ipv6fragmentationTestSuite
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:1035
virtual int Send(Ptr< Packet > p, uint32_t flags)=0
Send data (or dummy data) to the remote host.
static void AddInternetStack(Ptr< Node > node)
void SetChannel(Ptr< SimpleChannel > channel)
Attach a channel to this net device.
void SetAttribute(std::string name, const AttributeValue &value)
Definition: object-base.cc:161
Ptr< T > GetObject(void) const
Definition: object.h:361
a unique identifier for an interface.
Definition: type-id.h:49
void Enable(void)
Enable the error model.
Definition: error-model.cc:125
virtual void SetUp(uint32_t interface)=0
Set the interface into the "up" state.