A Discrete-Event Network Simulator
API
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 "ns3/simple-net-device.h"
28 #include "ns3/socket.h"
29 #include "ns3/udp-socket.h"
30 
31 #include "ns3/log.h"
32 #include "ns3/node.h"
33 #include "ns3/inet-socket-address.h"
34 #include "ns3/boolean.h"
35 
36 #include "ns3/sixlowpan-net-device.h"
37 #include "ns3/internet-stack-helper.h"
38 #include "ns3/icmpv6-l4-protocol.h"
39 #include "ns3/error-channel.h"
40 
41 #include <string>
42 #include <limits>
43 #include <netinet/in.h>
44 
45 using namespace ns3;
46 
53 {
57 
60  uint32_t m_dataSize;
61  uint8_t *m_data;
62  uint32_t m_size;
63  uint8_t m_icmpType;
64  uint8_t m_icmpCode;
65 
66 public:
67  virtual void DoRun (void);
70 
71  // server part
72 
77  void StartServer (Ptr<Node> serverNode);
82  void HandleReadServer (Ptr<Socket> socket);
83 
84  // client part
85 
90  void StartClient (Ptr<Node> clientNode);
95  void HandleReadClient (Ptr<Socket> socket);
104  void HandleReadIcmpClient (Ipv6Address icmpSource, uint8_t icmpTtl, uint8_t icmpType,
105  uint8_t icmpCode, uint32_t icmpInfo);
112  void SetFill (uint8_t *fill, uint32_t fillSize, uint32_t dataSize);
117  Ptr<Packet> SendClient (void);
118 
119 };
120 
121 
123  : TestCase ("Verify the 6LoWPAN protocol fragmentation and reassembly")
124 {
125  m_socketServer = 0;
126  m_data = 0;
127  m_dataSize = 0;
128  m_size = 0;
129  m_icmpType = 0;
130  m_icmpCode = 0;
131 }
132 
134 {
135  if ( m_data )
136  {
137  delete[] m_data;
138  }
139  m_data = 0;
140  m_dataSize = 0;
141 }
142 
143 
144 void
146 {
147 
148  if (m_socketServer == 0)
149  {
150  TypeId tid = TypeId::LookupByName ("ns3::UdpSocketFactory");
151  m_socketServer = Socket::CreateSocket (serverNode, tid);
152  Inet6SocketAddress local = Inet6SocketAddress (Ipv6Address ("2001:0100::1"), 9);
153  m_socketServer->Bind (local);
154  Ptr<UdpSocket> udpSocket = DynamicCast<UdpSocket> (m_socketServer);
155  }
156 
158 }
159 
160 void
162 {
163  Ptr<Packet> packet;
164  Address from;
165  while ((packet = socket->RecvFrom (from)))
166  {
167  if (Inet6SocketAddress::IsMatchingType (from))
168  {
169  packet->RemoveAllPacketTags ();
170  packet->RemoveAllByteTags ();
171 
172  m_receivedPacketServer = packet->Copy ();
173  }
174  }
175 }
176 
177 void
179 {
180 
181  if (m_socketClient == 0)
182  {
183  TypeId tid = TypeId::LookupByName ("ns3::UdpSocketFactory");
184  m_socketClient = Socket::CreateSocket (clientNode, tid);
185  m_socketClient->Bind (Inet6SocketAddress (Ipv6Address::GetAny (), 9));
186  m_socketClient->Connect (Inet6SocketAddress (Ipv6Address ("2001:0100::1"), 9));
188  m_socketClient->SetAttribute ("IcmpCallback6", cbValue);
189  }
190 
192 }
193 
194 void
196 {
197  Ptr<Packet> packet;
198  Address from;
199  while ((packet = socket->RecvFrom (from)))
200  {
201  if (Inet6SocketAddress::IsMatchingType (from))
202  {
203  m_receivedPacketClient = packet->Copy ();
204  }
205  }
206 }
207 
208 void
210  uint8_t icmpTtl, uint8_t icmpType,
211  uint8_t icmpCode, uint32_t icmpInfo)
212 {
213  m_icmpType = icmpType;
214  m_icmpCode = icmpCode;
215 }
216 
217 void
218 SixlowpanFragmentationTest::SetFill (uint8_t *fill, uint32_t fillSize, uint32_t dataSize)
219 {
220  if (dataSize != m_dataSize)
221  {
222  delete [] m_data;
223  m_data = new uint8_t [dataSize];
224  m_dataSize = dataSize;
225  }
226 
227  if (fillSize >= dataSize)
228  {
229  memcpy (m_data, fill, dataSize);
230  return;
231  }
232 
233  uint32_t filled = 0;
234  while (filled + fillSize < dataSize)
235  {
236  memcpy (&m_data[filled], fill, fillSize);
237  filled += fillSize;
238  }
239 
240  memcpy (&m_data[filled], fill, dataSize - filled);
241 
242  m_size = dataSize;
243 }
244 
246 {
247  Ptr<Packet> p;
248  if (m_dataSize)
249  {
250  p = Create<Packet> (m_data, m_dataSize);
251  }
252  else
253  {
254  p = Create<Packet> (m_size);
255  }
256  m_socketClient->Send (p);
257 
258  return p;
259 }
260 
261 void
263 {
264  // Create topology
265  InternetStackHelper internet;
266  internet.SetIpv4StackInstall (false);
267  Packet::EnablePrinting ();
268 
269  // Receiver Node
270  Ptr<Node> serverNode = CreateObject<Node> ();
271  internet.Install (serverNode);
272  Ptr<SimpleNetDevice> serverDev;
273  Ptr<BinaryErrorModel> serverDevErrorModel = CreateObject<BinaryErrorModel> ();
274  {
275  Ptr<Icmpv6L4Protocol> icmpv6l4 = serverNode->GetObject<Icmpv6L4Protocol> ();
276  icmpv6l4->SetAttribute ("DAD", BooleanValue (false));
277 
278  serverDev = CreateObject<SimpleNetDevice> ();
279  serverDev->SetAddress (Mac48Address::ConvertFrom (Mac48Address::Allocate ()));
280  serverDev->SetMtu (1500);
281  serverDev->SetReceiveErrorModel (serverDevErrorModel);
282  serverDevErrorModel->Disable ();
283  serverNode->AddDevice (serverDev);
284 
285  Ptr<SixLowPanNetDevice> serverSix = CreateObject<SixLowPanNetDevice> ();
286  serverSix->SetAttribute ("ForceEtherType", BooleanValue (true) );
287  serverNode->AddDevice (serverSix);
288  serverSix->SetNetDevice (serverDev);
289 
290  Ptr<Ipv6> ipv6 = serverNode->GetObject<Ipv6> ();
291  ipv6->AddInterface (serverDev);
292  uint32_t netdev_idx = ipv6->AddInterface (serverSix);
293  Ipv6InterfaceAddress ipv6Addr = Ipv6InterfaceAddress (Ipv6Address ("2001:0100::1"), Ipv6Prefix (64));
294  ipv6->AddAddress (netdev_idx, ipv6Addr);
295  ipv6->SetUp (netdev_idx);
296 
297  }
298  StartServer (serverNode);
299 
300  // Sender Node
301  Ptr<Node> clientNode = CreateObject<Node> ();
302  internet.Install (clientNode);
303  Ptr<SimpleNetDevice> clientDev;
304  Ptr<BinaryErrorModel> clientDevErrorModel = CreateObject<BinaryErrorModel> ();
305  {
306  Ptr<Icmpv6L4Protocol> icmpv6l4 = clientNode->GetObject<Icmpv6L4Protocol> ();
307  icmpv6l4->SetAttribute ("DAD", BooleanValue (false));
308 
309  clientDev = CreateObject<SimpleNetDevice> ();
310  clientDev->SetAddress (Mac48Address::ConvertFrom (Mac48Address::Allocate ()));
311  clientDev->SetMtu (150);
312  clientDev->SetReceiveErrorModel (clientDevErrorModel);
313  clientDevErrorModel->Disable ();
314  clientNode->AddDevice (clientDev);
315 
316  Ptr<SixLowPanNetDevice> clientSix = CreateObject<SixLowPanNetDevice> ();
317  clientSix->SetAttribute ("ForceEtherType", BooleanValue (true) );
318  clientNode->AddDevice (clientSix);
319  clientSix->SetNetDevice (clientDev);
320 
321  Ptr<Ipv6> ipv6 = clientNode->GetObject<Ipv6> ();
322  ipv6->AddInterface (clientDev);
323  uint32_t netdev_idx = ipv6->AddInterface (clientSix);
324  Ipv6InterfaceAddress ipv6Addr = Ipv6InterfaceAddress (Ipv6Address ("2001:0100::2"), Ipv6Prefix (64));
325  ipv6->AddAddress (netdev_idx, ipv6Addr);
326  ipv6->SetUp (netdev_idx);
327  }
328  StartClient (clientNode);
329 
330  // link the two nodes
331  Ptr<ErrorChannel> channel = CreateObject<ErrorChannel> ();
332  serverDev->SetChannel (channel);
333  clientDev->SetChannel (channel);
334 
335 
336  // some small packets, some rather big ones
337  uint32_t packetSizes[5] = {200, 300, 400, 500, 600};
338 
339  // using the alphabet
340  uint8_t fillData[78];
341  for ( uint32_t k = 48; k <= 125; k++ )
342  {
343  fillData[k - 48] = k;
344  }
345 
346  // First test: normal channel, no errors, no delays
347  for ( int i = 0; i < 5; i++)
348  {
349  uint32_t packetSize = packetSizes[i];
350 
351  SetFill (fillData, 78, packetSize);
352 
353  m_receivedPacketServer = Create<Packet> ();
354  Simulator::ScheduleWithContext (m_socketClient->GetNode ()->GetId (), Seconds (0),
356  Simulator::Run ();
357 
358  uint8_t recvBuffer[65000];
359 
360  uint16_t recvSize = m_receivedPacketServer->GetSize ();
361 
362  NS_TEST_EXPECT_MSG_EQ (recvSize, packetSizes[i],
363  "Packet size not correct: recvSize: " << recvSize << " packetSizes[" << i << "]: " << packetSizes[i] );
364 
365  m_receivedPacketServer->CopyData (recvBuffer, 65000);
366  NS_TEST_EXPECT_MSG_EQ (memcmp (m_data, recvBuffer, m_receivedPacketServer->GetSize ()),
367  0, "Packet content differs");
368  }
369 
370  // Second test: normal channel, no errors, delays each 2 packets.
371  // Each other fragment will arrive out-of-order.
372  // The packets should be received correctly since reassembly will reorder the fragments.
373  channel->SetJumpingMode (true);
374  for ( int i = 0; i < 5; i++)
375  {
376  uint32_t packetSize = packetSizes[i];
377 
378  SetFill (fillData, 78, packetSize);
379 
380  m_receivedPacketServer = Create<Packet> ();
381  Simulator::ScheduleWithContext (m_socketClient->GetNode ()->GetId (), Seconds (0),
383  Simulator::Run ();
384 
385  uint8_t recvBuffer[65000];
386 
387  uint16_t recvSize = m_receivedPacketServer->GetSize ();
388 
389  NS_TEST_EXPECT_MSG_EQ (recvSize, packetSizes[i],
390  "Packet size not correct: recvSize: " << recvSize << " packetSizes[" << i << "]: " << packetSizes[i] );
391 
392  m_receivedPacketServer->CopyData (recvBuffer, 65000);
393  NS_TEST_EXPECT_MSG_EQ (memcmp (m_data, recvBuffer, m_receivedPacketServer->GetSize ()),
394  0, "Packet content differs");
395  }
396  channel->SetJumpingMode (false);
397 
398 
399  // Third test: normal channel, some packets are duplicate.
400  // The duplicate fragments should be discarded, so no error should be fired.
401  channel->SetDuplicateMode (true);
402  for ( int i = 1; i < 5; i++)
403  {
404  uint32_t packetSize = packetSizes[i];
405 
406  SetFill (fillData, 78, packetSize);
407 
408  // reset the model, we want to receive the very first fragment.
409  serverDevErrorModel->Reset ();
410 
411  m_receivedPacketServer = Create<Packet> ();
412  m_icmpType = 0;
413  m_icmpCode = 0;
414  Simulator::ScheduleWithContext (m_socketClient->GetNode ()->GetId (), Seconds (0),
416  Simulator::Run ();
417 
418  uint8_t recvBuffer[65000];
419 
420  uint16_t recvSize = m_receivedPacketServer->GetSize ();
421 
422  NS_TEST_EXPECT_MSG_EQ (recvSize, packetSizes[i],
423  "Packet size not correct: recvSize: " << recvSize << " packetSizes[" << i << "]: " << packetSizes[i] );
424 
425  m_receivedPacketServer->CopyData (recvBuffer, 65000);
426  NS_TEST_EXPECT_MSG_EQ (memcmp (m_data, recvBuffer, m_receivedPacketServer->GetSize ()),
427  0, "Packet content differs");
428  }
429  channel->SetDuplicateMode (false);
430 
431  // Fourth test: normal channel, some errors, no delays.
432  // The reassembly procedure does NOT fire any ICMP, so we do not expect any reply from the server.
433  // Client -> Server : errors enabled
434  // Server -> Client : errors disabled
435  clientDevErrorModel->Disable ();
436  serverDevErrorModel->Enable ();
437  for ( int i = 1; i < 5; i++)
438  {
439  uint32_t packetSize = packetSizes[i];
440 
441  SetFill (fillData, 78, packetSize);
442 
443  // reset the model, we want to receive the very first fragment.
444  serverDevErrorModel->Reset ();
445 
446  m_receivedPacketServer = Create<Packet> ();
447  m_icmpType = 0;
448  m_icmpCode = 0;
449  Simulator::ScheduleWithContext (m_socketClient->GetNode ()->GetId (), Seconds (0),
451  Simulator::Run ();
452 
453  uint16_t recvSize = m_receivedPacketServer->GetSize ();
454 
455  NS_TEST_EXPECT_MSG_EQ ((recvSize == 0), true, "Server got a packet, something wrong");
456  // Note that a 6LoWPAN fragment timeout does NOT send any ICMPv6.
457  }
458 
459  Simulator::Destroy ();
460 }
461 
462 
469 {
470 public:
472 private:
473 };
474 
476  : TestSuite ("sixlowpan-fragmentation", UNIT)
477 {
478  AddTestCase (new SixlowpanFragmentationTest (), TestCase::QUICK);
479 }
480 
Ptr< Packet > m_sentPacketClient
Packet sent by client.
void StartClient(Ptr< Node > clientNode)
Start the client node.
void StartServer(Ptr< Node > serverNode)
Start the server node.
Ptr< Socket > m_socketServer
Socket on the server.
Ptr< Socket > m_socketClient
Socket on the client.
void SetFill(uint8_t *fill, uint32_t fillSize, uint32_t dataSize)
Set the packet optional content.
void HandleReadIcmpClient(Ipv6Address icmpSource, uint8_t icmpTtl, uint8_t icmpType, uint8_t icmpCode, uint32_t icmpInfo)
Handles incoming ICMP packets in the client.
Ptr< Packet > m_receivedPacketServer
packet received by the server.
void HandleReadServer(Ptr< Socket > socket)
Handles incoming packets in the server.
uint32_t m_dataSize
Size of the data (if any).
void HandleReadClient(Ptr< Socket > socket)
Handles incoming packets in the client.
Ptr< Packet > SendClient(void)
Send a packet to the server.
uint32_t m_size
Size of the packet if no data has been provided.
virtual void DoRun(void)
Implementation to actually run this TestCase.
Ptr< Packet > m_receivedPacketClient
Packet received by the client.
uint8_t * m_data
Data to be carried in the packet.
a polymophic address class
Definition: address.h:91
AttributeValue implementation for Boolean.
Definition: boolean.h:37
AttributeValue implementation for Callback.
Definition: callback.h:1944
An implementation of the ICMPv6 protocol.
An Inet6 address class.
aggregate IP/TCP/UDP functionality to existing Nodes.
void SetIpv4StackInstall(bool enable)
Enable/disable IPv4 stack install.
void Install(std::string nodeName) const
Aggregate implementations of the ns3::Ipv4, ns3::Ipv6, ns3::Udp, and ns3::Tcp classes onto the provid...
Describes an IPv6 address.
Definition: ipv6-address.h:50
Access to the IPv6 forwarding table, interfaces, and configuration.
Definition: ipv6.h:82
IPv6 address associated with an interface.
Describes an IPv6 prefix.
Definition: ipv6-address.h:456
uint32_t GetId(void) const
Definition: node.cc:109
uint32_t AddDevice(Ptr< NetDevice > device)
Associate a NetDevice to this node.
Definition: node.cc:130
void SetAttribute(std::string name, const AttributeValue &value)
Set a single attribute, raising fatal errors if unsuccessful.
Definition: object-base.cc:256
Ptr< T > GetObject(void) const
Get a pointer to the requested aggregated Object.
Definition: object.h:470
void RemoveAllByteTags(void)
Remove all byte tags stored in this packet.
Definition: packet.cc:371
uint32_t CopyData(uint8_t *buffer, uint32_t size) const
Copy the packet contents to a byte buffer.
Definition: packet.cc:378
void RemoveAllPacketTags(void)
Remove all packet tags.
Definition: packet.cc:984
Ptr< Packet > Copy(void) const
performs a COW copy of the packet.
Definition: packet.cc:121
uint32_t GetSize(void) const
Returns the the size in bytes of the packet (including the zero-filled initial payload).
Definition: packet.h:856
virtual int Send(Ptr< Packet > p, uint32_t flags)=0
Send data (or dummy data) to the remote host.
virtual int Connect(const Address &address)=0
Initiate a connection to a remote host.
virtual Ptr< Node > GetNode(void) const =0
Return the node this socket is associated with.
void SetRecvCallback(Callback< void, Ptr< Socket > > receivedData)
Notify application when new data is available to be read.
Definition: socket.cc:128
virtual int Bind(const Address &address)=0
Allocate a local endpoint for this socket.
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.
encapsulates test code
Definition: test.h:994
void AddTestCase(TestCase *testCase, TestDuration duration=QUICK)
Add an individual child TestCase to this test suite.
Definition: test.cc:299
A suite of tests to run.
Definition: test.h:1188
a unique identifier for an interface.
Definition: type-id.h:59
#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:240
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1244
Every class exported by the ns3 library is enclosed in the ns3 namespace.
Callback< R, Ts... > MakeCallback(R(T::*memPtr)(Ts...), OBJ objPtr)
Build Callbacks for class method members which take varying numbers of arguments and potentially retu...
Definition: callback.h:1648
channel
Definition: third.py:92
static SixlowpanFragmentationTestSuite g_sixlowpanFragmentationTestSuite
Static variable for test initialization.
static const uint32_t packetSize