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 "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/sixlowpan-net-device.h"
39 #include "ns3/internet-stack-helper.h"
40 #include "ns3/icmpv6-l4-protocol.h"
41 
42 #include <string>
43 #include <limits>
44 #include <netinet/in.h>
45 
46 using namespace ns3;
47 
49 {
53 
56  uint32_t m_dataSize;
57  uint8_t *m_data;
58  uint32_t m_size;
59  uint8_t m_icmpType;
60  uint8_t m_icmpCode;
61 
62 public:
63  virtual void DoRun (void);
66 
67  // server part
68  void StartServer (Ptr<Node> ServerNode);
69  void HandleReadServer (Ptr<Socket> socket);
70 
71  // client part
72  void StartClient (Ptr<Node> ClientNode);
73  void HandleReadClient (Ptr<Socket> socket);
74  void HandleReadIcmpClient (Ipv6Address icmpSource, uint8_t icmpTtl, uint8_t icmpType,
75  uint8_t icmpCode,uint32_t icmpInfo);
76 
77  void SetFill (uint8_t *fill, uint32_t fillSize, uint32_t dataSize);
78  Ptr<Packet> SendClient (void);
79 
80 };
81 
82 
84  : TestCase ("Verify the 6LoWPAN protocol fragmentation and reassembly")
85 {
86  m_socketServer = 0;
87  m_data = 0;
88  m_dataSize = 0;
89  m_size = 0;
90  m_icmpType = 0;
91  m_icmpCode = 0;
92 }
93 
95 {
96  if ( m_data )
97  {
98  delete[] m_data;
99  }
100  m_data = 0;
101  m_dataSize = 0;
102 }
103 
104 
105 void
107 {
108 
109  if (m_socketServer == 0)
110  {
111  TypeId tid = TypeId::LookupByName ("ns3::UdpSocketFactory");
112  m_socketServer = Socket::CreateSocket (ServerNode, tid);
113  Inet6SocketAddress local = Inet6SocketAddress (Ipv6Address ("2001:0100::1"), 9);
114  m_socketServer->Bind (local);
115  Ptr<UdpSocket> udpSocket = DynamicCast<UdpSocket> (m_socketServer);
116  }
117 
119 }
120 
121 void
123 {
124  Ptr<Packet> packet;
125  Address from;
126  while ((packet = socket->RecvFrom (from)))
127  {
128  if (Inet6SocketAddress::IsMatchingType (from))
129  {
130  packet->RemoveAllPacketTags ();
131  packet->RemoveAllByteTags ();
132 
133  m_receivedPacketServer = packet->Copy ();
134  }
135  }
136 }
137 
138 void
140 {
141 
142  if (m_socketClient == 0)
143  {
144  TypeId tid = TypeId::LookupByName ("ns3::UdpSocketFactory");
145  m_socketClient = Socket::CreateSocket (ClientNode, tid);
146  m_socketClient->Bind (Inet6SocketAddress (Ipv6Address::GetAny (), 9));
147  m_socketClient->Connect (Inet6SocketAddress (Ipv6Address ("2001:0100::1"), 9));
149  m_socketClient->SetAttribute ("IcmpCallback6", cbValue);
150  }
151 
153 }
154 
155 void
157 {
158  Ptr<Packet> packet;
159  Address from;
160  while ((packet = socket->RecvFrom (from)))
161  {
162  if (Inet6SocketAddress::IsMatchingType (from))
163  {
164  m_receivedPacketClient = packet->Copy ();
165  }
166  }
167 }
168 
169 void
171  uint8_t icmpTtl, uint8_t icmpType,
172  uint8_t icmpCode, uint32_t icmpInfo)
173 {
174  m_icmpType = icmpType;
175  m_icmpCode = icmpCode;
176 }
177 
178 void
179 SixlowpanFragmentationTest::SetFill (uint8_t *fill, uint32_t fillSize, uint32_t dataSize)
180 {
181  if (dataSize != m_dataSize)
182  {
183  delete [] m_data;
184  m_data = new uint8_t [dataSize];
185  m_dataSize = dataSize;
186  }
187 
188  if (fillSize >= dataSize)
189  {
190  memcpy (m_data, fill, dataSize);
191  return;
192  }
193 
194  uint32_t filled = 0;
195  while (filled + fillSize < dataSize)
196  {
197  memcpy (&m_data[filled], fill, fillSize);
198  filled += fillSize;
199  }
200 
201  memcpy (&m_data[filled], fill, dataSize - filled);
202 
203  m_size = dataSize;
204 }
205 
207 {
208  Ptr<Packet> p;
209  if (m_dataSize)
210  {
211  p = Create<Packet> (m_data, m_dataSize);
212  }
213  else
214  {
215  p = Create<Packet> (m_size);
216  }
217  m_socketClient->Send (p);
218 
219  return p;
220 }
221 
222 void
224 {
225  // Create topology
226  InternetStackHelper internet;
227  internet.SetIpv4StackInstall (false);
228  Packet::EnablePrinting ();
229 
230  // Receiver Node
231  Ptr<Node> serverNode = CreateObject<Node> ();
232  internet.Install (serverNode);
233  Ptr<SimpleNetDevice> serverDev;
234  Ptr<BinaryErrorSixlowModel> serverDevErrorModel = CreateObject<BinaryErrorSixlowModel> ();
235  {
236  Ptr<Icmpv6L4Protocol> icmpv6l4 = serverNode->GetObject<Icmpv6L4Protocol> ();
237  icmpv6l4->SetAttribute ("DAD", BooleanValue (false));
238 
239  serverDev = CreateObject<SimpleNetDevice> ();
240  serverDev->SetAddress (Mac48Address::ConvertFrom (Mac48Address::Allocate ()));
241  serverDev->SetMtu (1500);
242  serverDev->SetReceiveErrorModel (serverDevErrorModel);
243  serverDevErrorModel->Disable ();
244  serverNode->AddDevice (serverDev);
245 
246  Ptr<SixLowPanNetDevice> serverSix = CreateObject<SixLowPanNetDevice> ();
247  serverSix->SetAttribute ("ForceEtherType", BooleanValue (true) );
248  serverNode->AddDevice (serverSix);
249  serverSix->SetNetDevice (serverDev);
250 
251  Ptr<Ipv6> ipv6 = serverNode->GetObject<Ipv6> ();
252  ipv6->AddInterface (serverDev);
253  uint32_t netdev_idx = ipv6->AddInterface (serverSix);
254  Ipv6InterfaceAddress ipv6Addr = Ipv6InterfaceAddress (Ipv6Address ("2001:0100::1"), Ipv6Prefix (64));
255  ipv6->AddAddress (netdev_idx, ipv6Addr);
256  ipv6->SetUp (netdev_idx);
257 
258  }
259  StartServer (serverNode);
260 
261  // Sender Node
262  Ptr<Node> clientNode = CreateObject<Node> ();
263  internet.Install (clientNode);
264  Ptr<SimpleNetDevice> clientDev;
265  Ptr<BinaryErrorSixlowModel> clientDevErrorModel = CreateObject<BinaryErrorSixlowModel> ();
266  {
267  Ptr<Icmpv6L4Protocol> icmpv6l4 = clientNode->GetObject<Icmpv6L4Protocol> ();
268  icmpv6l4->SetAttribute ("DAD", BooleanValue (false));
269 
270  clientDev = CreateObject<SimpleNetDevice> ();
271  clientDev->SetAddress (Mac48Address::ConvertFrom (Mac48Address::Allocate ()));
272  clientDev->SetMtu (150);
273  clientDev->SetReceiveErrorModel (clientDevErrorModel);
274  clientDevErrorModel->Disable ();
275  clientNode->AddDevice (clientDev);
276 
277  Ptr<SixLowPanNetDevice> clientSix = CreateObject<SixLowPanNetDevice> ();
278  clientSix->SetAttribute ("ForceEtherType", BooleanValue (true) );
279  clientNode->AddDevice (clientSix);
280  clientSix->SetNetDevice (clientDev);
281 
282  Ptr<Ipv6> ipv6 = clientNode->GetObject<Ipv6> ();
283  ipv6->AddInterface (clientDev);
284  uint32_t netdev_idx = ipv6->AddInterface (clientSix);
285  Ipv6InterfaceAddress ipv6Addr = Ipv6InterfaceAddress (Ipv6Address ("2001:0100::2"), Ipv6Prefix (64));
286  ipv6->AddAddress (netdev_idx, ipv6Addr);
287  ipv6->SetUp (netdev_idx);
288  }
289  StartClient (clientNode);
290 
291  // link the two nodes
292  Ptr<ErrorChannelSixlow> channel = CreateObject<ErrorChannelSixlow> ();
293  serverDev->SetChannel (channel);
294  clientDev->SetChannel (channel);
295 
296 
297  // some small packets, some rather big ones
298  uint32_t packetSizes[5] = {200, 300, 400, 500, 600};
299 
300  // using the alphabet
301  uint8_t fillData[78];
302  for ( uint32_t k = 48; k <= 125; k++ )
303  {
304  fillData[k - 48] = k;
305  }
306 
307  // First test: normal channel, no errors, no delays
308  for ( int i = 0; i < 5; i++)
309  {
310  uint32_t packetSize = packetSizes[i];
311 
312  SetFill (fillData, 78, packetSize);
313 
314  m_receivedPacketServer = Create<Packet> ();
315  Simulator::ScheduleWithContext (m_socketClient->GetNode ()->GetId (), Seconds (0),
317  Simulator::Run ();
318 
319  uint8_t recvBuffer[65000];
320 
321  uint16_t recvSize = m_receivedPacketServer->GetSize ();
322 
323  NS_TEST_EXPECT_MSG_EQ (recvSize, packetSizes[i],
324  "Packet size not correct: recvSize: " << recvSize << " packetSizes[" << i << "]: " << packetSizes[i] );
325 
326  m_receivedPacketServer->CopyData (recvBuffer, 65000);
327  NS_TEST_EXPECT_MSG_EQ (memcmp (m_data, recvBuffer, m_receivedPacketServer->GetSize ()),
328  0, "Packet content differs");
329  }
330 
331  // Second test: normal channel, no errors, delays each 2 packets.
332  // Each other fragment will arrive out-of-order.
333  // The packets should be received correctly since reassembly will reorder the fragments.
334  channel->SetJumpingMode (true);
335  for ( int i = 0; i < 5; i++)
336  {
337  uint32_t packetSize = packetSizes[i];
338 
339  SetFill (fillData, 78, packetSize);
340 
341  m_receivedPacketServer = Create<Packet> ();
342  Simulator::ScheduleWithContext (m_socketClient->GetNode ()->GetId (), Seconds (0),
344  Simulator::Run ();
345 
346  uint8_t recvBuffer[65000];
347 
348  uint16_t recvSize = m_receivedPacketServer->GetSize ();
349 
350  NS_TEST_EXPECT_MSG_EQ (recvSize, packetSizes[i],
351  "Packet size not correct: recvSize: " << recvSize << " packetSizes[" << i << "]: " << packetSizes[i] );
352 
353  m_receivedPacketServer->CopyData (recvBuffer, 65000);
354  NS_TEST_EXPECT_MSG_EQ (memcmp (m_data, recvBuffer, m_receivedPacketServer->GetSize ()),
355  0, "Packet content differs");
356  }
357  channel->SetJumpingMode (false);
358 
359 
360  // Third test: normal channel, some packets are duplicate.
361  // The duplicate fragments should be discarded, so no error should be fired.
362  channel->SetDuplicateMode (true);
363  for ( int i = 1; i < 5; i++)
364  {
365  uint32_t packetSize = packetSizes[i];
366 
367  SetFill (fillData, 78, packetSize);
368 
369  // reset the model, we want to receive the very first fragment.
370  serverDevErrorModel->Reset ();
371 
372  m_receivedPacketServer = Create<Packet> ();
373  m_icmpType = 0;
374  m_icmpCode = 0;
375  Simulator::ScheduleWithContext (m_socketClient->GetNode ()->GetId (), Seconds (0),
377  Simulator::Run ();
378 
379  uint8_t recvBuffer[65000];
380 
381  uint16_t recvSize = m_receivedPacketServer->GetSize ();
382 
383  NS_TEST_EXPECT_MSG_EQ (recvSize, packetSizes[i],
384  "Packet size not correct: recvSize: " << recvSize << " packetSizes[" << i << "]: " << packetSizes[i] );
385 
386  m_receivedPacketServer->CopyData (recvBuffer, 65000);
387  NS_TEST_EXPECT_MSG_EQ (memcmp (m_data, recvBuffer, m_receivedPacketServer->GetSize ()),
388  0, "Packet content differs");
389  }
390  channel->SetDuplicateMode (false);
391 
392  // Fourth test: normal channel, some errors, no delays.
393  // The reassembly procedure does NOT fire any ICMP, so we do not expect any reply from the server.
394  // Client -> Server : errors enabled
395  // Server -> Client : errors disabled
396  clientDevErrorModel->Disable ();
397  serverDevErrorModel->Enable ();
398  for ( int i = 1; i < 5; i++)
399  {
400  uint32_t packetSize = packetSizes[i];
401 
402  SetFill (fillData, 78, packetSize);
403 
404  // reset the model, we want to receive the very first fragment.
405  serverDevErrorModel->Reset ();
406 
407  m_receivedPacketServer = Create<Packet> ();
408  m_icmpType = 0;
409  m_icmpCode = 0;
410  Simulator::ScheduleWithContext (m_socketClient->GetNode ()->GetId (), Seconds (0),
412  Simulator::Run ();
413 
414  uint16_t recvSize = m_receivedPacketServer->GetSize ();
415 
416  NS_TEST_EXPECT_MSG_EQ ((recvSize == 0), true, "Server got a packet, something wrong");
417  // Note that a 6LoWPAN fragment timeout does NOT send any ICMPv6.
418  }
419 
420 
421 
422  Simulator::Destroy ();
423 }
424 //-----------------------------------------------------------------------------
426 {
427 public:
428  SixlowpanFragmentationTestSuite () : TestSuite ("sixlowpan-fragmentation", UNIT)
429  {
430  AddTestCase (new SixlowpanFragmentationTest, TestCase::QUICK);
431  }
tuple channel
Definition: third.py:85
AttributeValue implementation for Boolean.
Definition: boolean.h:34
Ptr< T > GetObject(void) const
Get a pointer to the requested aggregated Object.
Definition: object.h:462
Access to the IPv6 forwarding table, interfaces, and configuration.
Definition: ipv6.h:81
A suite of tests to run.
Definition: test.h:1333
IPv6 address associated with an interface.
aggregate IP/TCP/UDP functionality to existing Nodes.
#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:278
uint32_t GetSize(void) const
Returns the the size in bytes of the packet (including the zero-filled initial payload).
Definition: packet.h:792
encapsulates test code
Definition: test.h:1147
This test suite implements a Unit Test.
Definition: test.h:1343
void SetNetDevice(Ptr< NetDevice > device)
Setup SixLowPan to be a proxy for the specified NetDevice.
a polymophic address class
Definition: address.h:90
AttributeValue implementation for Callback.
Definition: callback.h:1880
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:852
void AddTestCase(TestCase *testCase, enum TestDuration duration)
Add an individual child TestCase to this test suite.
Definition: test.cc:298
virtual bool SetMtu(const uint16_t mtu)
void SetIpv4StackInstall(bool enable)
Enable/disable IPv4 stack install.
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:1489
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
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.
Every class exported by the ns3 library is enclosed in the ns3 namespace.
void Install(std::string nodeName) const
Aggregate implementations of the ns3::Ipv4, ns3::Ipv6, ns3::Udp, and ns3::Tcp classes onto the provid...
void SetReceiveErrorModel(Ptr< ErrorModel > em)
Attach a receive ErrorModel to the SimpleNetDevice.
void HandleReadServer(Ptr< Socket > socket)
virtual uint32_t AddInterface(Ptr< NetDevice > device)=0
Add a NetDevice interface.
void StartServer(Ptr< Node > ServerNode)
void HandleReadClient(Ptr< Socket > socket)
Describes an IPv6 address.
Definition: ipv6-address.h:48
SixlowpanFragmentationTestSuite g_sixlowpanFragmentationTestSuite
uint32_t AddDevice(Ptr< NetDevice > device)
Associate a NetDevice to this node.
Definition: node.cc:128
uint32_t GetId(void) const
Definition: node.cc:107
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:895
void RemoveAllByteTags(void)
Remove all byte tags stored in this packet.
Definition: packet.cc:349
Describes an IPv6 prefix.
Definition: ipv6-address.h:394
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:356
static const uint32_t packetSize
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)
virtual int Send(Ptr< Packet > p, uint32_t flags)=0
Send data (or dummy data) to the remote host.
void SetChannel(Ptr< SimpleChannel > channel)
Attach a channel to this net device.
void SetAttribute(std::string name, const AttributeValue &value)
Set a single attribute, raising fatal errors if unsuccessful.
Definition: object-base.cc:191
a unique identifier for an interface.
Definition: type-id.h:58
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.