A Discrete-Event Network Simulator
API
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
ipv6-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  */
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
67 AddInternetStack (Ptr<Node> node)
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 {
95  Ptr<Packet> m_sentPacketClient;
96  Ptr<Packet> m_receivedPacketClient;
97  Ptr<Packet> m_receivedPacketServer;
98 
99 
100  Ptr<Socket> m_socketServer;
101  Ptr<Socket> m_socketClient;
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 
129 Ipv6FragmentationTest::Ipv6FragmentationTest ()
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 
137 Ipv6FragmentationTest::~Ipv6FragmentationTest ()
138 {
139  if ( m_data )
140  {
141  delete[] m_data;
142  }
143  m_data = 0;
144  m_dataSize = 0;
145 }
146 
147 
148 void
149 Ipv6FragmentationTest::StartServer (Ptr<Node> ServerNode)
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 
161  m_socketServer->SetRecvCallback (MakeCallback (&Ipv6FragmentationTest::HandleReadServer, this));
162 }
163 
164 void
165 Ipv6FragmentationTest::HandleReadServer (Ptr<Socket> socket)
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
182 Ipv6FragmentationTest::StartClient (Ptr<Node> ClientNode)
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));
190  m_socketClient->Connect (Inet6SocketAddress (Ipv6Address ("2001::1"), 9));
191  CallbackValue cbValue = MakeCallback (&Ipv6FragmentationTest::HandleReadIcmpClient, this);
192  m_socketClient->SetAttribute ("IcmpCallback6", cbValue);
193  }
194 
195  m_socketClient->SetRecvCallback (MakeCallback (&Ipv6FragmentationTest::HandleReadClient, this));
196 }
197 
198 void
199 Ipv6FragmentationTest::HandleReadClient (Ptr<Socket> socket)
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
213 Ipv6FragmentationTest::HandleReadIcmpClient (Ipv6Address icmpSource,
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 
249 Ptr<Packet> Ipv6FragmentationTest::SendClient (void)
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),
341  &Ipv6FragmentationTest::SendClient, this);
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),
368  &Ipv6FragmentationTest::SendClient, this);
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),
406  &Ipv6FragmentationTest::SendClient, this);
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  {
426  AddTestCase (new Ipv6FragmentationTest, TestCase::QUICK);
427  }
428 } g_ipv6fragmentationTestSuite;
Access to the IPv6 forwarding table, interfaces, and configuration.
Definition: ipv6.h:79
A suite of tests to run.
Definition: test.h:962
IPv6 address associated with an interface.
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
An Inet6 address class.
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)
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
virtual uint32_t AddInterface(Ptr< NetDevice > device)=0
Add a NetDevice interface.
virtual void DoRun(void)
Implementation to actually run this test case.
virtual void RegisterExtensions()
Register the IPv6 Extensions.
Describes an IPv6 address.
Definition: ipv6-address.h:44
void SetRoutingProtocol(Ptr< Ipv6RoutingProtocol > routingProtocol)
Set routing protocol for this stack.
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
virtual Ptr< Node > GetNode(void) const =0
void RemoveAllByteTags(void)
Definition: packet.cc:378
virtual void RegisterOptions()
Register the IPv6 Options.
Describes an IPv6 prefix. It is just a bitmask like Ipv4Mask.
Definition: ipv6-address.h:326
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
Definition: packet.cc:398
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
virtual void SetUp(uint32_t interface)=0
Set the interface into the "up" state.