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 
54 {
58 
61  uint32_t m_dataSize;
62  uint8_t *m_data;
63  uint32_t m_size;
64  uint8_t m_icmpType;
65  uint8_t m_icmpCode;
66 
67 public:
68  virtual void DoRun (void);
71 
72  // server part
73 
78  void StartServer (Ptr<Node> serverNode);
83  void HandleReadServer (Ptr<Socket> socket);
84 
85  // client part
86 
91  void StartClient (Ptr<Node> clientNode);
96  void HandleReadClient (Ptr<Socket> socket);
105  void HandleReadIcmpClient (Ipv6Address icmpSource, uint8_t icmpTtl, uint8_t icmpType,
106  uint8_t icmpCode, uint32_t icmpInfo);
113  void SetFill (uint8_t *fill, uint32_t fillSize, uint32_t dataSize);
118  Ptr<Packet> SendClient (void);
119 
120 };
121 
122 
124  : TestCase ("Verify the 6LoWPAN protocol fragmentation and reassembly")
125 {
126  m_socketServer = 0;
127  m_data = 0;
128  m_dataSize = 0;
129  m_size = 0;
130  m_icmpType = 0;
131  m_icmpCode = 0;
132 }
133 
135 {
136  if ( m_data )
137  {
138  delete[] m_data;
139  }
140  m_data = 0;
141  m_dataSize = 0;
142 }
143 
144 
145 void
147 {
148 
149  if (m_socketServer == 0)
150  {
151  TypeId tid = TypeId::LookupByName ("ns3::UdpSocketFactory");
152  m_socketServer = Socket::CreateSocket (serverNode, tid);
153  Inet6SocketAddress local = Inet6SocketAddress (Ipv6Address ("2001:0100::1"), 9);
154  m_socketServer->Bind (local);
155  Ptr<UdpSocket> udpSocket = DynamicCast<UdpSocket> (m_socketServer);
156  }
157 
159 }
160 
161 void
163 {
164  Ptr<Packet> packet;
165  Address from;
166  while ((packet = socket->RecvFrom (from)))
167  {
168  if (Inet6SocketAddress::IsMatchingType (from))
169  {
170  packet->RemoveAllPacketTags ();
171  packet->RemoveAllByteTags ();
172 
173  m_receivedPacketServer = packet->Copy ();
174  }
175  }
176 }
177 
178 void
180 {
181 
182  if (m_socketClient == 0)
183  {
184  TypeId tid = TypeId::LookupByName ("ns3::UdpSocketFactory");
185  m_socketClient = Socket::CreateSocket (clientNode, tid);
186  m_socketClient->Bind (Inet6SocketAddress (Ipv6Address::GetAny (), 9));
187  m_socketClient->Connect (Inet6SocketAddress (Ipv6Address ("2001:0100::1"), 9));
189  m_socketClient->SetAttribute ("IcmpCallback6", cbValue);
190  }
191 
193 }
194 
195 void
197 {
198  Ptr<Packet> packet;
199  Address from;
200  while ((packet = socket->RecvFrom (from)))
201  {
202  if (Inet6SocketAddress::IsMatchingType (from))
203  {
204  m_receivedPacketClient = packet->Copy ();
205  }
206  }
207 }
208 
209 void
211  uint8_t icmpTtl, uint8_t icmpType,
212  uint8_t icmpCode, uint32_t icmpInfo)
213 {
214  m_icmpType = icmpType;
215  m_icmpCode = icmpCode;
216 }
217 
218 void
219 SixlowpanFragmentationTest::SetFill (uint8_t *fill, uint32_t fillSize, uint32_t dataSize)
220 {
221  if (dataSize != m_dataSize)
222  {
223  delete [] m_data;
224  m_data = new uint8_t [dataSize];
225  m_dataSize = dataSize;
226  }
227 
228  if (fillSize >= dataSize)
229  {
230  memcpy (m_data, fill, dataSize);
231  return;
232  }
233 
234  uint32_t filled = 0;
235  while (filled + fillSize < dataSize)
236  {
237  memcpy (&m_data[filled], fill, fillSize);
238  filled += fillSize;
239  }
240 
241  memcpy (&m_data[filled], fill, dataSize - filled);
242 
243  m_size = dataSize;
244 }
245 
247 {
248  Ptr<Packet> p;
249  if (m_dataSize)
250  {
251  p = Create<Packet> (m_data, m_dataSize);
252  }
253  else
254  {
255  p = Create<Packet> (m_size);
256  }
257  m_socketClient->Send (p);
258 
259  return p;
260 }
261 
262 void
264 {
265  // Create topology
266  InternetStackHelper internet;
267  internet.SetIpv4StackInstall (false);
268  Packet::EnablePrinting ();
269 
270  // Receiver Node
271  Ptr<Node> serverNode = CreateObject<Node> ();
272  internet.Install (serverNode);
273  Ptr<SimpleNetDevice> serverDev;
274  Ptr<BinaryErrorModel> serverDevErrorModel = CreateObject<BinaryErrorModel> ();
275  {
276  Ptr<Icmpv6L4Protocol> icmpv6l4 = serverNode->GetObject<Icmpv6L4Protocol> ();
277  icmpv6l4->SetAttribute ("DAD", BooleanValue (false));
278 
279  serverDev = CreateObject<SimpleNetDevice> ();
280  serverDev->SetAddress (Mac48Address::ConvertFrom (Mac48Address::Allocate ()));
281  serverDev->SetMtu (1500);
282  serverDev->SetReceiveErrorModel (serverDevErrorModel);
283  serverDevErrorModel->Disable ();
284  serverNode->AddDevice (serverDev);
285 
286  Ptr<SixLowPanNetDevice> serverSix = CreateObject<SixLowPanNetDevice> ();
287  serverSix->SetAttribute ("ForceEtherType", BooleanValue (true) );
288  serverNode->AddDevice (serverSix);
289  serverSix->SetNetDevice (serverDev);
290 
291  Ptr<Ipv6> ipv6 = serverNode->GetObject<Ipv6> ();
292  ipv6->AddInterface (serverDev);
293  uint32_t netdev_idx = ipv6->AddInterface (serverSix);
294  Ipv6InterfaceAddress ipv6Addr = Ipv6InterfaceAddress (Ipv6Address ("2001:0100::1"), Ipv6Prefix (64));
295  ipv6->AddAddress (netdev_idx, ipv6Addr);
296  ipv6->SetUp (netdev_idx);
297 
298  }
299  StartServer (serverNode);
300 
301  // Sender Node
302  Ptr<Node> clientNode = CreateObject<Node> ();
303  internet.Install (clientNode);
304  Ptr<SimpleNetDevice> clientDev;
305  Ptr<BinaryErrorModel> clientDevErrorModel = CreateObject<BinaryErrorModel> ();
306  {
307  Ptr<Icmpv6L4Protocol> icmpv6l4 = clientNode->GetObject<Icmpv6L4Protocol> ();
308  icmpv6l4->SetAttribute ("DAD", BooleanValue (false));
309 
310  clientDev = CreateObject<SimpleNetDevice> ();
311  clientDev->SetAddress (Mac48Address::ConvertFrom (Mac48Address::Allocate ()));
312  clientDev->SetMtu (150);
313  clientDev->SetReceiveErrorModel (clientDevErrorModel);
314  clientDevErrorModel->Disable ();
315  clientNode->AddDevice (clientDev);
316 
317  Ptr<SixLowPanNetDevice> clientSix = CreateObject<SixLowPanNetDevice> ();
318  clientSix->SetAttribute ("ForceEtherType", BooleanValue (true) );
319  clientNode->AddDevice (clientSix);
320  clientSix->SetNetDevice (clientDev);
321 
322  Ptr<Ipv6> ipv6 = clientNode->GetObject<Ipv6> ();
323  ipv6->AddInterface (clientDev);
324  uint32_t netdev_idx = ipv6->AddInterface (clientSix);
325  Ipv6InterfaceAddress ipv6Addr = Ipv6InterfaceAddress (Ipv6Address ("2001:0100::2"), Ipv6Prefix (64));
326  ipv6->AddAddress (netdev_idx, ipv6Addr);
327  ipv6->SetUp (netdev_idx);
328  }
329  StartClient (clientNode);
330 
331  // link the two nodes
332  Ptr<ErrorChannel> channel = CreateObject<ErrorChannel> ();
333  serverDev->SetChannel (channel);
334  clientDev->SetChannel (channel);
335 
336 
337  // some small packets, some rather big ones
338  uint32_t packetSizes[5] = {200, 300, 400, 500, 600};
339 
340  // using the alphabet
341  uint8_t fillData[78];
342  for ( uint32_t k = 48; k <= 125; k++ )
343  {
344  fillData[k - 48] = k;
345  }
346 
347  // First test: normal channel, no errors, no delays
348  for ( int i = 0; i < 5; i++)
349  {
350  uint32_t packetSize = packetSizes[i];
351 
352  SetFill (fillData, 78, packetSize);
353 
354  m_receivedPacketServer = Create<Packet> ();
355  Simulator::ScheduleWithContext (m_socketClient->GetNode ()->GetId (), Seconds (0),
357  Simulator::Run ();
358 
359  uint8_t recvBuffer[65000];
360 
361  uint16_t recvSize = m_receivedPacketServer->GetSize ();
362 
363  NS_TEST_EXPECT_MSG_EQ (recvSize, packetSizes[i],
364  "Packet size not correct: recvSize: " << recvSize << " packetSizes[" << i << "]: " << packetSizes[i] );
365 
366  m_receivedPacketServer->CopyData (recvBuffer, 65000);
367  NS_TEST_EXPECT_MSG_EQ (memcmp (m_data, recvBuffer, m_receivedPacketServer->GetSize ()),
368  0, "Packet content differs");
369  }
370 
371  // Second test: normal channel, no errors, delays each 2 packets.
372  // Each other fragment will arrive out-of-order.
373  // The packets should be received correctly since reassembly will reorder the fragments.
374  channel->SetJumpingMode (true);
375  for ( int i = 0; i < 5; i++)
376  {
377  uint32_t packetSize = packetSizes[i];
378 
379  SetFill (fillData, 78, packetSize);
380 
381  m_receivedPacketServer = Create<Packet> ();
382  Simulator::ScheduleWithContext (m_socketClient->GetNode ()->GetId (), Seconds (0),
384  Simulator::Run ();
385 
386  uint8_t recvBuffer[65000];
387 
388  uint16_t recvSize = m_receivedPacketServer->GetSize ();
389 
390  NS_TEST_EXPECT_MSG_EQ (recvSize, packetSizes[i],
391  "Packet size not correct: recvSize: " << recvSize << " packetSizes[" << i << "]: " << packetSizes[i] );
392 
393  m_receivedPacketServer->CopyData (recvBuffer, 65000);
394  NS_TEST_EXPECT_MSG_EQ (memcmp (m_data, recvBuffer, m_receivedPacketServer->GetSize ()),
395  0, "Packet content differs");
396  }
397  channel->SetJumpingMode (false);
398 
399 
400  // Third test: normal channel, some packets are duplicate.
401  // The duplicate fragments should be discarded, so no error should be fired.
402  channel->SetDuplicateMode (true);
403  for ( int i = 1; i < 5; i++)
404  {
405  uint32_t packetSize = packetSizes[i];
406 
407  SetFill (fillData, 78, packetSize);
408 
409  // reset the model, we want to receive the very first fragment.
410  serverDevErrorModel->Reset ();
411 
412  m_receivedPacketServer = Create<Packet> ();
413  m_icmpType = 0;
414  m_icmpCode = 0;
415  Simulator::ScheduleWithContext (m_socketClient->GetNode ()->GetId (), Seconds (0),
417  Simulator::Run ();
418 
419  uint8_t recvBuffer[65000];
420 
421  uint16_t recvSize = m_receivedPacketServer->GetSize ();
422 
423  NS_TEST_EXPECT_MSG_EQ (recvSize, packetSizes[i],
424  "Packet size not correct: recvSize: " << recvSize << " packetSizes[" << i << "]: " << packetSizes[i] );
425 
426  m_receivedPacketServer->CopyData (recvBuffer, 65000);
427  NS_TEST_EXPECT_MSG_EQ (memcmp (m_data, recvBuffer, m_receivedPacketServer->GetSize ()),
428  0, "Packet content differs");
429  }
430  channel->SetDuplicateMode (false);
431 
432  // Fourth test: normal channel, some errors, no delays.
433  // The reassembly procedure does NOT fire any ICMP, so we do not expect any reply from the server.
434  // Client -> Server : errors enabled
435  // Server -> Client : errors disabled
436  clientDevErrorModel->Disable ();
437  serverDevErrorModel->Enable ();
438  for ( int i = 1; i < 5; i++)
439  {
440  uint32_t packetSize = packetSizes[i];
441 
442  SetFill (fillData, 78, packetSize);
443 
444  // reset the model, we want to receive the very first fragment.
445  serverDevErrorModel->Reset ();
446 
447  m_receivedPacketServer = Create<Packet> ();
448  m_icmpType = 0;
449  m_icmpCode = 0;
450  Simulator::ScheduleWithContext (m_socketClient->GetNode ()->GetId (), Seconds (0),
452  Simulator::Run ();
453 
454  uint16_t recvSize = m_receivedPacketServer->GetSize ();
455 
456  NS_TEST_EXPECT_MSG_EQ ((recvSize == 0), true, "Server got a packet, something wrong");
457  // Note that a 6LoWPAN fragment timeout does NOT send any ICMPv6.
458  }
459 
460  Simulator::Destroy ();
461 }
462 
463 
471 {
472 public:
474 private:
475 };
476 
478  : TestSuite ("sixlowpan-fragmentation", UNIT)
479 {
480  AddTestCase (new SixlowpanFragmentationTest (), TestCase::QUICK);
481 }
482 
tuple channel
Definition: third.py:85
AttributeValue implementation for Boolean.
Definition: boolean.h:36
Ptr< T > GetObject(void) const
Get a pointer to the requested aggregated Object.
Definition: object.h:459
Access to the IPv6 forwarding table, interfaces, and configuration.
Definition: ipv6.h:81
A suite of tests to run.
Definition: test.h:1342
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:285
uint32_t GetSize(void) const
Returns the the size in bytes of the packet (including the zero-filled initial payload).
Definition: packet.h:796
encapsulates test code
Definition: test.h:1155
Ptr< Packet > m_sentPacketClient
Packet sent by client.
Ptr< Socket > m_socketClient
Socket on the client.
void SetNetDevice(Ptr< NetDevice > device)
Setup SixLowPan to be a proxy for the specified NetDevice.
void StartServer(Ptr< Node > serverNode)
Start the server node.
Ptr< Packet > m_receivedPacketServer
packet received by the server.
a polymophic address class
Definition: address.h:90
AttributeValue implementation for Callback.
Definition: callback.h:1880
void RemoveAllPacketTags(void)
Remove all packet tags.
Definition: packet.cc:842
void AddTestCase(TestCase *testCase, TestDuration duration=QUICK)
Add an individual child TestCase to this test suite.
Definition: test.cc:299
uint32_t m_size
Size of the packet if no data has been provided.
virtual bool SetMtu(const uint16_t mtu)
void SetIpv4StackInstall(bool enable)
Enable/disable IPv4 stack install.
An Inet6 address class.
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
6LoWPAN Fragmentation TestSuite
void Disable(void)
Disable the error model.
Definition: error-model.cc:132
static SixlowpanFragmentationTestSuite g_sixlowpanFragmentationTestSuite
Static variable for test initialization.
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:121
Ptr< Packet > m_receivedPacketClient
Packet received by the client.
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 SetDuplicateMode(bool mode)
Set if the odd packets are duplicated (even ones are not duplicated ever)
void StartClient(Ptr< Node > clientNode)
Start the client node.
Ptr< Socket > m_socketServer
Socket on the server.
void Install(std::string nodeName) const
Aggregate implementations of the ns3::Ipv4, ns3::Ipv6, ns3::Udp, and ns3::Tcp classes onto the provid...
void Reset(void)
Reset any state associated with the error model.
Definition: error-model.cc:118
void SetReceiveErrorModel(Ptr< ErrorModel > em)
Attach a receive ErrorModel to the SimpleNetDevice.
void HandleReadServer(Ptr< Socket > socket)
Handles incoming packets in the server.
virtual uint32_t AddInterface(Ptr< NetDevice > device)=0
Add a NetDevice interface.
void HandleReadClient(Ptr< Socket > socket)
Handles incoming packets in the client.
Describes an IPv6 address.
Definition: ipv6-address.h:48
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.
Ptr< Packet > SendClient(void)
Send a packet to the server.
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:993
void RemoveAllByteTags(void)
Remove all byte tags stored in this packet.
Definition: packet.cc:348
uint8_t * m_data
Data to be carried in the packet.
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:355
static const uint32_t packetSize
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)
Handles incoming ICMP packets in the client.
virtual int Send(Ptr< Packet > p, uint32_t flags)=0
Send data (or dummy data) to the remote host.
uint32_t m_dataSize
Size of the data (if any).
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:185
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)
Set the packet optional content.
virtual void SetUp(uint32_t interface)=0
Set the interface into the "up" state.
virtual void DoRun(void)
Implementation to actually run this TestCase.