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