A Discrete-Event Network Simulator
API
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
sixlowpan-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) 2013 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  */
20 #define NS3_LOG_ENABLE 1
21 
22 #include "ns3/test.h"
23 #include "ns3/config.h"
24 #include "ns3/uinteger.h"
25 #include "ns3/socket-factory.h"
26 #include "ns3/ipv6-raw-socket-factory.h"
27 #include "ns3/udp-socket-factory.h"
28 #include "ns3/simulator.h"
29 #include "error-channel-sixlow.h"
30 #include "ns3/simple-net-device.h"
31 #include "ns3/drop-tail-queue.h"
32 #include "ns3/socket.h"
33 #include "ns3/udp-socket.h"
34 
35 #include "ns3/log.h"
36 #include "ns3/node.h"
37 #include "ns3/inet-socket-address.h"
38 #include "ns3/boolean.h"
39 
40 #include "ns3/ipv6-static-routing.h"
41 #include "ns3/ipv6-list-routing.h"
42 #include "ns3/inet6-socket-address.h"
43 #include "ns3/sixlowpan-net-device.h"
44 
45 #include "ns3/udp-l4-protocol.h"
46 
47 #include "ns3/ipv6-l3-protocol.h"
48 #include "ns3/icmpv6-l4-protocol.h"
49 
50 #include <string>
51 #include <limits>
52 #include <netinet/in.h>
53 
54 using namespace ns3;
55 
56 class UdpSocketImpl;
57 
58 static void
60 {
61  //IPV6
62  Ptr<Ipv6L3Protocol> ipv6 = CreateObject<Ipv6L3Protocol> ();
63 
64  //Routing for Ipv6
65  Ptr<Ipv6ListRouting> ipv6Routing = CreateObject<Ipv6ListRouting> ();
66  ipv6->SetRoutingProtocol (ipv6Routing);
67  Ptr<Ipv6StaticRouting> ipv6staticRouting = CreateObject<Ipv6StaticRouting> ();
68  ipv6Routing->AddRoutingProtocol (ipv6staticRouting, 0);
69  node->AggregateObject (ipv6);
70 
71  //ICMPv6
72  Ptr<Icmpv6L4Protocol> icmp6 = CreateObject<Icmpv6L4Protocol> ();
73  node->AggregateObject (icmp6);
74 
75  //Ipv6 Extensions
76  ipv6->RegisterExtensions ();
77  ipv6->RegisterOptions ();
78 
79  //UDP
80  Ptr<UdpL4Protocol> udp = CreateObject<UdpL4Protocol> ();
81  node->AggregateObject (udp);
82 }
83 
84 
86 {
90 
91 
94  uint32_t m_dataSize;
95  uint8_t *m_data;
96  uint32_t m_size;
97  uint8_t m_icmpType;
98  uint8_t m_icmpCode;
99 
100 public:
101  virtual void DoRun (void);
104 
105  // server part
106  void StartServer (Ptr<Node> ServerNode);
107  void HandleReadServer (Ptr<Socket> socket);
108 
109  // client part
110  void StartClient (Ptr<Node> ClientNode);
111  void HandleReadClient (Ptr<Socket> socket);
112  void HandleReadIcmpClient (Ipv6Address icmpSource, uint8_t icmpTtl, uint8_t icmpType,
113  uint8_t icmpCode,uint32_t icmpInfo);
114 
115  void SetFill (uint8_t *fill, uint32_t fillSize, uint32_t dataSize);
116  Ptr<Packet> SendClient (void);
117 
118 };
119 
120 
122  : TestCase ("Verify the 6LoWPAN protocol fragmentation and reassembly")
123 {
124  m_socketServer = 0;
125  m_data = 0;
126  m_dataSize = 0;
127 }
128 
130 {
131  if ( m_data )
132  {
133  delete[] m_data;
134  }
135  m_data = 0;
136  m_dataSize = 0;
137 }
138 
139 
140 void
142 {
143 
144  if (m_socketServer == 0)
145  {
146  TypeId tid = TypeId::LookupByName ("ns3::UdpSocketFactory");
147  m_socketServer = Socket::CreateSocket (ServerNode, tid);
148  Inet6SocketAddress local = Inet6SocketAddress (Ipv6Address ("2001:0100::1"), 9);
149  m_socketServer->Bind (local);
150  Ptr<UdpSocket> udpSocket = DynamicCast<UdpSocket> (m_socketServer);
151  }
152 
154 }
155 
156 void
158 {
159  Ptr<Packet> packet;
160  Address from;
161  while ((packet = socket->RecvFrom (from)))
162  {
163  if (Inet6SocketAddress::IsMatchingType (from))
164  {
165  packet->RemoveAllPacketTags ();
166  packet->RemoveAllByteTags ();
167 
168  m_receivedPacketServer = packet->Copy ();
169  }
170  }
171 }
172 
173 void
175 {
176 
177  if (m_socketClient == 0)
178  {
179  TypeId tid = TypeId::LookupByName ("ns3::UdpSocketFactory");
180  m_socketClient = Socket::CreateSocket (ClientNode, tid);
181  m_socketClient->Bind (Inet6SocketAddress (Ipv6Address::GetAny (), 9));
182  m_socketClient->Connect (Inet6SocketAddress (Ipv6Address ("2001:0100::1"), 9));
184  m_socketClient->SetAttribute ("IcmpCallback6", cbValue);
185  }
186 
188 }
189 
190 void
192 {
193  Ptr<Packet> packet;
194  Address from;
195  while ((packet = socket->RecvFrom (from)))
196  {
197  if (Inet6SocketAddress::IsMatchingType (from))
198  {
199  m_receivedPacketClient = packet->Copy ();
200  }
201  }
202 }
203 
204 void
206  uint8_t icmpTtl, uint8_t icmpType,
207  uint8_t icmpCode, uint32_t icmpInfo)
208 {
209  m_icmpType = icmpType;
210  m_icmpCode = icmpCode;
211 }
212 
213 void
214 SixlowpanFragmentationTest::SetFill (uint8_t *fill, uint32_t fillSize, uint32_t dataSize)
215 {
216  if (dataSize != m_dataSize)
217  {
218  delete [] m_data;
219  m_data = new uint8_t [dataSize];
220  m_dataSize = dataSize;
221  }
222 
223  if (fillSize >= dataSize)
224  {
225  memcpy (m_data, fill, dataSize);
226  return;
227  }
228 
229  uint32_t filled = 0;
230  while (filled + fillSize < dataSize)
231  {
232  memcpy (&m_data[filled], fill, fillSize);
233  filled += fillSize;
234  }
235 
236  memcpy (&m_data[filled], fill, dataSize - filled);
237 
238  m_size = dataSize;
239 }
240 
242 {
243  Ptr<Packet> p;
244  if (m_dataSize)
245  {
246  p = Create<Packet> (m_data, m_dataSize);
247  }
248  else
249  {
250  p = Create<Packet> (m_size);
251  }
252  m_socketClient->Send (p);
253 
254  return p;
255 }
256 
257 void
259 {
260  // Create topology
261 
262  // Receiver Node
263  Ptr<Node> serverNode = CreateObject<Node> ();
264  AddInternetStack (serverNode);
265  Ptr<SimpleNetDevice> serverDev;
266  Ptr<BinaryErrorSixlowModel> serverDevErrorModel = CreateObject<BinaryErrorSixlowModel> ();
267  {
268  serverDev = CreateObject<SimpleNetDevice> ();
269  serverDev->SetAddress (Mac48Address::ConvertFrom (Mac48Address::Allocate ()));
270  serverDev->SetMtu (1500);
271  serverDev->SetReceiveErrorModel (serverDevErrorModel);
272  serverDevErrorModel->Disable ();
273  serverNode->AddDevice (serverDev);
274 
275  Ptr<SixLowPanNetDevice> serverSix = CreateObject<SixLowPanNetDevice> ();
276  serverSix->SetAttribute ("ForceEtherType", BooleanValue (true) );
277  serverNode->AddDevice (serverSix);
278  serverSix->SetNetDevice (serverDev);
279 
280  Ptr<Ipv6> ipv6 = serverNode->GetObject<Ipv6> ();
281  ipv6->AddInterface (serverDev);
282  uint32_t netdev_idx = ipv6->AddInterface (serverSix);
283  Ipv6InterfaceAddress ipv6Addr = Ipv6InterfaceAddress (Ipv6Address ("2001:0100::1"), Ipv6Prefix (64));
284  ipv6->AddAddress (netdev_idx, ipv6Addr);
285  ipv6->SetUp (netdev_idx);
286 
287  Ptr<Icmpv6L4Protocol> icmpv6l4 = serverNode->GetObject<Icmpv6L4Protocol> ();
288  icmpv6l4->SetAttribute ("DAD", BooleanValue (false));
289  }
290  StartServer (serverNode);
291 
292  // Sender Node
293  Ptr<Node> clientNode = CreateObject<Node> ();
294  AddInternetStack (clientNode);
295  Ptr<SimpleNetDevice> clientDev;
296  Ptr<BinaryErrorSixlowModel> clientDevErrorModel = CreateObject<BinaryErrorSixlowModel> ();
297  {
298  clientDev = CreateObject<SimpleNetDevice> ();
299  clientDev->SetAddress (Mac48Address::ConvertFrom (Mac48Address::Allocate ()));
300  clientDev->SetMtu (150);
301  clientDev->SetReceiveErrorModel (clientDevErrorModel);
302  clientDevErrorModel->Disable ();
303  clientNode->AddDevice (clientDev);
304 
305  Ptr<SixLowPanNetDevice> clientSix = CreateObject<SixLowPanNetDevice> ();
306  clientSix->SetAttribute ("ForceEtherType", BooleanValue (true) );
307  serverNode->AddDevice (clientSix);
308  clientSix->SetNetDevice (clientDev);
309 
310  Ptr<Ipv6> ipv6 = clientNode->GetObject<Ipv6> ();
311  ipv6->AddInterface (clientDev);
312  uint32_t netdev_idx = ipv6->AddInterface (clientSix);
313  Ipv6InterfaceAddress ipv6Addr = Ipv6InterfaceAddress (Ipv6Address ("2001:0100::2"), Ipv6Prefix (64));
314  ipv6->AddAddress (netdev_idx, ipv6Addr);
315  ipv6->SetUp (netdev_idx);
316 
317  Ptr<Icmpv6L4Protocol> icmpv6l4 = clientNode->GetObject<Icmpv6L4Protocol> ();
318  icmpv6l4->SetAttribute ("DAD", BooleanValue (false));
319  }
320  StartClient (clientNode);
321 
322  // link the two nodes
323  Ptr<ErrorChannelSixlow> channel = CreateObject<ErrorChannelSixlow> ();
324  serverDev->SetChannel (channel);
325  clientDev->SetChannel (channel);
326 
327 
328  // some small packets, some rather big ones
329  uint32_t packetSizes[5] = {200, 300, 400, 500, 600};
330 
331  // using the alphabet
332  uint8_t fillData[78];
333  for ( uint32_t k = 48; k <= 125; k++ )
334  {
335  fillData[k - 48] = k;
336  }
337 
338  // First test: normal channel, no errors, no delays
339  for ( int i = 0; i < 5; i++)
340  {
341  uint32_t packetSize = packetSizes[i];
342 
343  SetFill (fillData, 78, packetSize);
344 
345  m_receivedPacketServer = Create<Packet> ();
346  Simulator::ScheduleWithContext (m_socketClient->GetNode ()->GetId (), Seconds (0),
348  Simulator::Run ();
349 
350  uint8_t recvBuffer[65000];
351 
352  uint16_t recvSize = m_receivedPacketServer->GetSize ();
353 
354  NS_TEST_EXPECT_MSG_EQ (recvSize, packetSizes[i],
355  "Packet size not correct: recvSize: " << recvSize << " packetSizes[" << i << "]: " << packetSizes[i] );
356 
357  m_receivedPacketServer->CopyData (recvBuffer, 65000);
358  NS_TEST_EXPECT_MSG_EQ (memcmp (m_data, recvBuffer, m_receivedPacketServer->GetSize ()),
359  0, "Packet content differs");
360  }
361 
362  // Second test: normal channel, no errors, delays each 2 packets.
363  // Each other fragment will arrive out-of-order.
364  // The packets should be received correctly since reassembly will reorder the fragments.
365  channel->SetJumpingMode (true);
366  for ( int i = 0; i < 5; i++)
367  {
368  uint32_t packetSize = packetSizes[i];
369 
370  SetFill (fillData, 78, packetSize);
371 
372  m_receivedPacketServer = Create<Packet> ();
373  Simulator::ScheduleWithContext (m_socketClient->GetNode ()->GetId (), Seconds (0),
375  Simulator::Run ();
376 
377  uint8_t recvBuffer[65000];
378 
379  uint16_t recvSize = m_receivedPacketServer->GetSize ();
380 
381  NS_TEST_EXPECT_MSG_EQ (recvSize, packetSizes[i],
382  "Packet size not correct: recvSize: " << recvSize << " packetSizes[" << i << "]: " << packetSizes[i] );
383 
384  m_receivedPacketServer->CopyData (recvBuffer, 65000);
385  NS_TEST_EXPECT_MSG_EQ (memcmp (m_data, recvBuffer, m_receivedPacketServer->GetSize ()),
386  0, "Packet content differs");
387  }
388  channel->SetJumpingMode (false);
389 
390 
391  // Third test: normal channel, some packets are duplicate.
392  // The duplicate fragments should be discarded, so no error should be fired.
393  channel->SetDuplicateMode (true);
394  for ( int i = 1; i < 5; i++)
395  {
396  uint32_t packetSize = packetSizes[i];
397 
398  SetFill (fillData, 78, packetSize);
399 
400  // reset the model, we want to receive the very first fragment.
401  serverDevErrorModel->Reset ();
402 
403  m_receivedPacketServer = Create<Packet> ();
404  m_icmpType = 0;
405  m_icmpCode = 0;
406  Simulator::ScheduleWithContext (m_socketClient->GetNode ()->GetId (), Seconds (0),
408  Simulator::Run ();
409 
410  uint8_t recvBuffer[65000];
411 
412  uint16_t recvSize = m_receivedPacketServer->GetSize ();
413 
414  NS_TEST_EXPECT_MSG_EQ (recvSize, packetSizes[i],
415  "Packet size not correct: recvSize: " << recvSize << " packetSizes[" << i << "]: " << packetSizes[i] );
416 
417  m_receivedPacketServer->CopyData (recvBuffer, 65000);
418  NS_TEST_EXPECT_MSG_EQ (memcmp (m_data, recvBuffer, m_receivedPacketServer->GetSize ()),
419  0, "Packet content differs");
420  }
421  channel->SetDuplicateMode (false);
422 
423  // Fourth test: normal channel, some errors, no delays.
424  // The reassembly procedure does NOT fire any ICMP, so we do not expect any reply from the server.
425  // Client -> Server : errors enabled
426  // Server -> Client : errors disabled
427  clientDevErrorModel->Disable ();
428  serverDevErrorModel->Enable ();
429  for ( int i = 1; i < 5; i++)
430  {
431  uint32_t packetSize = packetSizes[i];
432 
433  SetFill (fillData, 78, packetSize);
434 
435  // reset the model, we want to receive the very first fragment.
436  serverDevErrorModel->Reset ();
437 
438  m_receivedPacketServer = Create<Packet> ();
439  m_icmpType = 0;
440  m_icmpCode = 0;
441  Simulator::ScheduleWithContext (m_socketClient->GetNode ()->GetId (), Seconds (0),
443  Simulator::Run ();
444 
445  uint16_t recvSize = m_receivedPacketServer->GetSize ();
446 
447  NS_TEST_EXPECT_MSG_EQ ((recvSize == 0), true, "Server got a packet, something wrong");
448  // Note that a 6LoWPAN fragment timeout does NOT send any ICMPv6.
449  }
450 
451 
452 
453  Simulator::Destroy ();
454 }
455 //-----------------------------------------------------------------------------
457 {
458 public:
459  SixlowpanFragmentationTestSuite () : TestSuite ("sixlowpan-fragmentation", UNIT)
460  {
461  AddTestCase (new SixlowpanFragmentationTest, TestCase::QUICK);
462  }
Hold a bool native type.
Definition: boolean.h:38
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 SetNetDevice(Ptr< NetDevice > device)
Setup SixLowPan to be a proxy for the specified NetDevice.
A sockets interface to UDP.
a polymophic address class
Definition: address.h:86
AttributeValue form of a Callback.
Definition: callback.h:1658
void SetJumpingMode(bool mode)
Set if the odd packets are delayed (even ones are not delayed ever)
void RemoveAllPacketTags(void)
Remove all packet tags.
Definition: packet.cc:869
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.
void StartClient(Ptr< Node > ClientNode)
An implementation of the ICMPv6 protocol.
Callback< R > MakeCallback(R(T::*memPtr)(void), OBJ objPtr)
Definition: callback.h:1238
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.
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 HandleReadServer(Ptr< Socket > socket)
void AddTestCase(TestCase *testCase) NS_DEPRECATED
Add an individual child TestCase case to this TestCase.
Definition: test.cc:173
virtual uint32_t AddInterface(Ptr< NetDevice > device)=0
Add a NetDevice interface.
void StartServer(Ptr< Node > ServerNode)
virtual void RegisterExtensions()
Register the IPv6 Extensions.
void HandleReadClient(Ptr< Socket > socket)
Describes an IPv6 address.
Definition: ipv6-address.h:46
void SetRoutingProtocol(Ptr< Ipv6RoutingProtocol > routingProtocol)
Set routing protocol for this stack.
SixlowpanFragmentationTestSuite g_sixlowpanFragmentationTestSuite
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
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 SetDuplicateMode(bool mode)
Set if the odd packets are duplicated (even ones are not duplicated ever)
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.
void HandleReadIcmpClient(Ipv6Address icmpSource, uint8_t icmpTtl, uint8_t icmpType, uint8_t icmpCode, uint32_t icmpInfo)
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
void SetFill(uint8_t *fill, uint32_t fillSize, uint32_t dataSize)
virtual void SetUp(uint32_t interface)=0
Set the interface into the "up" state.
virtual void DoRun(void)
Implementation to actually run this TestCase.