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  */
26 #include "ns3/test.h"
27 #include "ns3/config.h"
28 #include "ns3/uinteger.h"
29 #include "ns3/socket-factory.h"
30 #include "ns3/ipv4-raw-socket-factory.h"
31 #include "ns3/ipv6-raw-socket-factory.h"
32 #include "ns3/udp-socket-factory.h"
33 #include "ns3/simulator.h"
34 #include "error-channel.h"
35 #include "ns3/simple-net-device.h"
36 #include "ns3/drop-tail-queue.h"
37 #include "ns3/socket.h"
38 #include "ns3/udp-socket.h"
39 
40 #include "ns3/log.h"
41 #include "ns3/node.h"
42 #include "ns3/inet-socket-address.h"
43 #include "ns3/boolean.h"
44 
45 #include "ns3/ipv6-static-routing.h"
46 #include "ns3/ipv6-list-routing.h"
47 #include "ns3/inet6-socket-address.h"
48 #
49 #include "ns3/arp-l3-protocol.h"
50 #include "ns3/ipv4-l3-protocol.h"
51 #include "ns3/icmpv4-l4-protocol.h"
52 #include "ns3/ipv4-list-routing.h"
53 #include "ns3/ipv4-static-routing.h"
54 #include "ns3/udp-l4-protocol.h"
55 
56 #include "ns3/ipv6-l3-protocol.h"
57 #include "ns3/icmpv6-l4-protocol.h"
58 
59 #include <string>
60 #include <limits>
61 #include <netinet/in.h>
62 
63 using namespace ns3;
64 
65 class UdpSocketImpl;
66 
67 /* ----------------------------------------------------------------------------------
68  * Tag
69  --------------------------------------------------------------------------------- */
70 class IPv6TestTag : public Tag {
71 private:
72  uint64_t token;
73 public:
74  static TypeId GetTypeId () {
75  static TypeId tid = TypeId ("ns3::IPv6TestTag").SetParent<Tag> ().AddConstructor<IPv6TestTag> ();
76  return tid;
77  }
78  virtual TypeId GetInstanceTypeId () const { return GetTypeId (); }
79  virtual uint32_t GetSerializedSize () const { return sizeof (token); }
80  virtual void Serialize (TagBuffer buffer) const { buffer.WriteU64 (token); }
81  virtual void Deserialize (TagBuffer buffer) { token = buffer.ReadU64 (); }
82  virtual void Print (std::ostream &os) const { os << "token=" << token; }
83  void setToken (uint64_t token) { this->token = token; }
84  uint64_t getToken () { return token; }
85 };
86 
87 static void
89 {
90  //IPV6
91  Ptr<Ipv6L3Protocol> ipv6 = CreateObject<Ipv6L3Protocol> ();
92 
93  //Routing for Ipv6
94  Ptr<Ipv6ListRouting> ipv6Routing = CreateObject<Ipv6ListRouting> ();
95  ipv6->SetRoutingProtocol (ipv6Routing);
96  Ptr<Ipv6StaticRouting> ipv6staticRouting = CreateObject<Ipv6StaticRouting> ();
97  ipv6Routing->AddRoutingProtocol (ipv6staticRouting, 0);
98  node->AggregateObject (ipv6);
99 
100  //ICMPv6
101  Ptr<Icmpv6L4Protocol> icmp6 = CreateObject<Icmpv6L4Protocol> ();
102  node->AggregateObject (icmp6);
103 
104  //Ipv6 Extensions
105  ipv6->RegisterExtensions ();
106  ipv6->RegisterOptions ();
107 
108  //UDP
109  Ptr<UdpL4Protocol> udp = CreateObject<UdpL4Protocol> ();
110  node->AggregateObject (udp);
111 }
112 
113 
115 {
119 
120 
123  uint32_t m_dataSize;
124  uint8_t *m_data;
125  uint32_t m_size;
126  uint8_t m_icmpType;
127  uint8_t m_icmpCode;
128 
129 public:
130  virtual void DoRun (void);
133 
134  // server part
135  void StartServer (Ptr<Node> ServerNode);
136  void HandleReadServer (Ptr<Socket> socket);
137 
138  // client part
139  void StartClient (Ptr<Node> ClientNode);
140  void HandleReadClient (Ptr<Socket> socket);
141  void HandleReadIcmpClient (Ipv6Address icmpSource, uint8_t icmpTtl, uint8_t icmpType,
142  uint8_t icmpCode,uint32_t icmpInfo);
143 
144  void SetFill (uint8_t *fill, uint32_t fillSize, uint32_t dataSize);
145  Ptr<Packet> SendClient (void);
146 
147 };
148 
149 
151  : TestCase ("Verify the IPv6 layer 3 protocol fragmentation and reassembly")
152 {
153  m_socketServer = 0;
154  m_data = 0;
155  m_dataSize = 0;
156 }
157 
159 {
160  if ( m_data )
161  {
162  delete[] m_data;
163  }
164  m_data = 0;
165  m_dataSize = 0;
166 }
167 
168 
169 void
171 {
172 
173  if (m_socketServer == 0)
174  {
175  TypeId tid = TypeId::LookupByName ("ns3::UdpSocketFactory");
176  m_socketServer = Socket::CreateSocket (ServerNode, tid);
177  Inet6SocketAddress local = Inet6SocketAddress (Ipv6Address ("2001::1"), 9);
178  m_socketServer->Bind (local);
179  Ptr<UdpSocket> udpSocket = DynamicCast<UdpSocket> (m_socketServer);
180  }
181 
183 }
184 
185 void
187 {
188  Ptr<Packet> packet;
189  Address from;
190  while ((packet = socket->RecvFrom (from)))
191  {
192  if (Inet6SocketAddress::IsMatchingType (from))
193  {
194  m_receivedPacketServer = packet->Copy ();
195  }
196  }
197 }
198 
199 void
201 {
202 
203  if (m_socketClient == 0)
204  {
205  TypeId tid = TypeId::LookupByName ("ns3::UdpSocketFactory");
206  m_socketClient = Socket::CreateSocket (ClientNode, tid);
207  m_socketClient->Bind (Inet6SocketAddress (Ipv6Address::GetAny (), 9));
210  m_socketClient->SetAttribute ("IcmpCallback6", cbValue);
211  }
212 
214 }
215 
216 void
218 {
219  Ptr<Packet> packet;
220  Address from;
221  while ((packet = socket->RecvFrom (from)))
222  {
223  if (Inet6SocketAddress::IsMatchingType (from))
224  {
225  m_receivedPacketClient = packet->Copy ();
226  }
227  }
228 }
229 
230 void
232  uint8_t icmpTtl, uint8_t icmpType,
233  uint8_t icmpCode, uint32_t icmpInfo)
234 {
235  m_icmpType = icmpType;
236  m_icmpCode = icmpCode;
237 }
238 
239 void
240 Ipv6FragmentationTest::SetFill (uint8_t *fill, uint32_t fillSize, uint32_t dataSize)
241 {
242  if (dataSize != m_dataSize)
243  {
244  delete [] m_data;
245  m_data = new uint8_t [dataSize];
246  m_dataSize = dataSize;
247  }
248 
249  if (fillSize >= dataSize)
250  {
251  memcpy (m_data, fill, dataSize);
252  return;
253  }
254 
255  uint32_t filled = 0;
256  while (filled + fillSize < dataSize)
257  {
258  memcpy (&m_data[filled], fill, fillSize);
259  filled += fillSize;
260  }
261 
262  memcpy (&m_data[filled], fill, dataSize - filled);
263 
264  m_size = dataSize;
265 }
266 
268 {
269  Ptr<Packet> p;
270  if (m_dataSize)
271  {
272  p = Create<Packet> (m_data, m_dataSize);
273  }
274  else
275  {
276  p = Create<Packet> (m_size);
277  }
278  IPv6TestTag tag;
279  tag.setToken (42);
280  p->AddPacketTag (tag);
281  p->AddByteTag (tag);
282 
283  m_socketClient->Send (p);
284 
285  return p;
286 }
287 
288 void
290 {
291  // Create topology
292 
293  // Receiver Node
294  Ptr<Node> serverNode = CreateObject<Node> ();
295  AddInternetStack (serverNode);
296  Ptr<SimpleNetDevice> serverDev;
297  Ptr<BinaryErrorModel> serverDevErrorModel = CreateObject<BinaryErrorModel> ();
298  {
299  serverDev = CreateObject<SimpleNetDevice> ();
300  serverDev->SetAddress (Mac48Address::ConvertFrom (Mac48Address::Allocate ()));
301  serverDev->SetMtu (1500);
302  serverDev->SetReceiveErrorModel (serverDevErrorModel);
303  serverDevErrorModel->Disable ();
304  serverNode->AddDevice (serverDev);
305  Ptr<Ipv6> ipv6 = serverNode->GetObject<Ipv6> ();
306  uint32_t netdev_idx = ipv6->AddInterface (serverDev);
307  Ipv6InterfaceAddress ipv6Addr = Ipv6InterfaceAddress (Ipv6Address ("2001::1"), Ipv6Prefix (32));
308  ipv6->AddAddress (netdev_idx, ipv6Addr);
309  ipv6->SetUp (netdev_idx);
310  }
311  StartServer (serverNode);
312 
313  // Sender Node
314  Ptr<Node> clientNode = CreateObject<Node> ();
315  AddInternetStack (clientNode);
316  Ptr<SimpleNetDevice> clientDev;
317  Ptr<BinaryErrorModel> clientDevErrorModel = CreateObject<BinaryErrorModel> ();
318  {
319  clientDev = CreateObject<SimpleNetDevice> ();
320  clientDev->SetAddress (Mac48Address::ConvertFrom (Mac48Address::Allocate ()));
321  clientDev->SetMtu (1500);
322  clientDev->SetReceiveErrorModel (clientDevErrorModel);
323  clientDevErrorModel->Disable ();
324  clientNode->AddDevice (clientDev);
325  Ptr<Ipv6> ipv6 = clientNode->GetObject<Ipv6> ();
326  uint32_t netdev_idx = ipv6->AddInterface (clientDev);
327  Ipv6InterfaceAddress ipv6Addr = Ipv6InterfaceAddress (Ipv6Address ("2001::2"), Ipv6Prefix (32));
328  ipv6->AddAddress (netdev_idx, ipv6Addr);
329  ipv6->SetUp (netdev_idx);
330  }
331  StartClient (clientNode);
332 
333  // link the two nodes
334  Ptr<ErrorChannel> channel = CreateObject<ErrorChannel> ();
335  serverDev->SetChannel (channel);
336  clientDev->SetChannel (channel);
337  channel->SetJumpingTime (Seconds (0.5));
338 
339 
340  // some small packets, some rather big ones
341  uint32_t packetSizes[5] = {2000, 2500, 5000, 10000, 65000};
342 
343  // using the alphabet
344  uint8_t fillData[78];
345  for ( uint32_t k = 48; k <= 125; k++ )
346  {
347  fillData[k - 48] = k;
348  }
349 
350  // First test: normal channel, no errors, no delays
351  for ( int i = 0; i < 5; i++)
352  {
353  uint32_t packetSize = packetSizes[i];
354 
355  SetFill (fillData, 78, packetSize);
356 
357  m_receivedPacketServer = Create<Packet> ();
358  Simulator::ScheduleWithContext (m_socketClient->GetNode ()->GetId (), Seconds (0),
360  Simulator::Run ();
361 
362  uint8_t recvBuffer[65000];
363 
364  uint16_t recvSize = m_receivedPacketServer->GetSize ();
365 
366  NS_TEST_EXPECT_MSG_EQ (recvSize, packetSizes[i],
367  "Packet size not correct: recvSize: " << recvSize << " packetSizes[" << i << "]: " << packetSizes[i] );
368 
369  m_receivedPacketServer->CopyData (recvBuffer, 65000);
370  NS_TEST_EXPECT_MSG_EQ (memcmp (m_data, recvBuffer, m_receivedPacketServer->GetSize ()),
371  0, "Packet content differs");
372  }
373 
374  // Second test: normal channel, no errors, delays each 2 packets.
375  // Each other fragment will arrive out-of-order.
376  // The packets should be received correctly since reassembly will reorder the fragments.
377  channel->SetJumpingMode (true);
378  for ( int i = 0; i < 5; i++)
379  {
380  uint32_t packetSize = packetSizes[i];
381 
382  SetFill (fillData, 78, packetSize);
383 
384  m_receivedPacketServer = Create<Packet> ();
385  Simulator::ScheduleWithContext (m_socketClient->GetNode ()->GetId (), Seconds (0),
387  Simulator::Run ();
388 
389  uint8_t recvBuffer[65000];
390 
391  uint16_t recvSize = m_receivedPacketServer->GetSize ();
392 
393  NS_TEST_EXPECT_MSG_EQ (recvSize, packetSizes[i],
394  "Packet size not correct: recvSize: " << recvSize << " packetSizes[" << i << "]: " << packetSizes[i] );
395 
396  m_receivedPacketServer->CopyData (recvBuffer, 65000);
397  NS_TEST_EXPECT_MSG_EQ (memcmp (m_data, recvBuffer, m_receivedPacketServer->GetSize ()),
398  0, "Packet content differs");
399  }
400  channel->SetJumpingMode (false);
401 
402  // Third test: normal channel, some errors, no delays.
403  // The reassembly procedure should fire a timeout after 30 seconds (as specified in the RFCs).
404  // Upon the timeout, the fragments received so far are discarded and an ICMP should be sent back
405  // to the sender (if the first fragment has been received).
406  // In this test case the first fragment is received, so we do expect an ICMP.
407  // Client -> Server : errors enabled
408  // Server -> Client : errors disabled (we want to have back the ICMP)
409  clientDevErrorModel->Disable ();
410  serverDevErrorModel->Enable ();
411  for ( int i = 1; i < 5; i++)
412  {
413  uint32_t packetSize = packetSizes[i];
414 
415  SetFill (fillData, 78, packetSize);
416 
417  // reset the model, we want to receive the very first fragment.
418  serverDevErrorModel->Reset ();
419 
420  m_receivedPacketServer = Create<Packet> ();
421  m_icmpType = 0;
422  m_icmpCode = 0;
423  Simulator::ScheduleWithContext (m_socketClient->GetNode ()->GetId (), Seconds (0),
425  Simulator::Run ();
426 
427  uint16_t recvSize = m_receivedPacketServer->GetSize ();
428 
429  NS_TEST_EXPECT_MSG_EQ ((recvSize == 0), true, "Server got a packet, something wrong");
430  NS_TEST_EXPECT_MSG_EQ ((m_icmpType == Icmpv6Header::ICMPV6_ERROR_TIME_EXCEEDED)
431  && (m_icmpCode == Icmpv6Header::ICMPV6_FRAGTIME),
432  true, "Client did not receive ICMPv6::TIME_EXCEEDED " << int(m_icmpType) << int(m_icmpCode) );
433  }
434 
435  // Fourth test: normal channel, no errors, no delays.
436  // We check tags
437  clientDevErrorModel->Disable ();
438  serverDevErrorModel->Disable ();
439  for (int i= 0; i<5; i++)
440  {
441  uint32_t packetSize = packetSizes[i];
442 
443  SetFill (fillData, 78, packetSize);
444 
445  m_receivedPacketServer = Create<Packet> ();
446  Simulator::ScheduleWithContext (m_socketClient->GetNode ()->GetId (), Seconds (0),
448  Simulator::Run ();
449 
450  IPv6TestTag packetTag;
451  bool found = m_receivedPacketServer->PeekPacketTag (packetTag);
452 
453  NS_TEST_EXPECT_MSG_EQ (found, true, "PacketTag not found");
454  NS_TEST_EXPECT_MSG_EQ (packetTag.getToken (), 42, "PacketTag value not correct");
455 
457 
458  uint32_t end = 0;
459  uint32_t tagStart = 0;
460  uint32_t tagEnd = 0;
461  while (iter.HasNext ())
462  {
463  ByteTagIterator::Item item = iter.Next ();
464  NS_TEST_EXPECT_MSG_EQ (item.GetTypeId ().GetName (), "ns3::IPv6TestTag", "ByteTag name not correct");
465  tagStart = item.GetStart ();
466  tagEnd = item.GetEnd ();
467  if (end == 0)
468  {
469  NS_TEST_EXPECT_MSG_EQ (tagStart, 0, "First ByteTag Start not correct");
470  }
471  if (end != 0)
472  {
473  NS_TEST_EXPECT_MSG_EQ (tagStart, end, "ByteTag End not correct");
474  }
475  end = tagEnd;
476  IPv6TestTag *byteTag = dynamic_cast<IPv6TestTag *> (item.GetTypeId ().GetConstructor () ());
477  NS_TEST_EXPECT_MSG_NE (byteTag, 0, "ByteTag not found");
478  item.GetTag (*byteTag);
479  NS_TEST_EXPECT_MSG_EQ (byteTag->getToken (), 42, "ByteTag value not correct");
480  delete byteTag;
481  }
483  }
484 
485  Simulator::Destroy ();
486 }
487 //-----------------------------------------------------------------------------
489 {
490 public:
491  Ipv6FragmentationTestSuite () : TestSuite ("ipv6-fragmentation", UNIT)
492  {
493  AddTestCase (new Ipv6FragmentationTest, TestCase::QUICK);
494  }
Access to the IPv6 forwarding table, interfaces, and configuration.
Definition: ipv6.h:80
void WriteU64(uint64_t v)
Definition: tag-buffer.cc:102
static TypeId GetTypeId()
A suite of tests to run.
Definition: test.h:1105
void AddPacketTag(const Tag &tag) const
Add a packet tag.
Definition: packet.cc:841
virtual uint32_t GetSerializedSize() const
IPv6 address associated with an interface.
#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
virtual void Print(std::ostream &os) const
encapsulates test code
Definition: test.h:929
void StartServer(Ptr< Node > ServerNode)
A sockets interface to UDP.
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
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
void HandleReadIcmpClient(Ipv6Address icmpSource, uint8_t icmpTtl, uint8_t icmpType, uint8_t icmpCode, uint32_t icmpInfo)
virtual bool SetMtu(const uint16_t mtu)
An Inet6 address class.
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 HandleReadClient(Ptr< Socket > socket)
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
virtual void Deserialize(TagBuffer buffer)
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
performs a COW copy of the packet.
Definition: packet.cc:122
tag a set of bytes in a packet
Definition: tag.h:36
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
void SetReceiveErrorModel(Ptr< ErrorModel > em)
Attach a receive ErrorModel to the SimpleNetDevice.
TypeId GetTypeId(void) const
Definition: packet.cc:34
void AddTestCase(TestCase *testCase) NS_DEPRECATED
Add an individual child TestCase case to this TestCase.
Definition: test.cc:184
virtual TypeId GetInstanceTypeId() const
void HandleReadServer(Ptr< Socket > socket)
Ptr< Packet > SendClient(void)
virtual uint32_t AddInterface(Ptr< NetDevice > device)=0
Add a NetDevice interface.
void GetTag(Tag &tag) const
Read the requested tag and store it in the user-provided tag instance.
Definition: packet.cc:49
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.
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
virtual Ptr< Node > GetNode(void) const =0
Return the node this socket is associated with.
virtual void Serialize(TagBuffer buffer) const
virtual void SetAddress(Address address)
Set the address of this interface.
void SetFill(uint8_t *fill, uint32_t fillSize, uint32_t dataSize)
virtual void RegisterOptions()
Register the IPv6 Options.
void setToken(uint64_t token)
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:1115
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: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
virtual void SetUp(uint32_t interface)=0
Set the interface into the "up" state.
void AddByteTag(const Tag &tag) const
Tag each byte included in this packet with a new byte tag.
Definition: packet.cc:808