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 
AttributeValue implementation for Boolean.
Definition: boolean.h:36
uint32_t GetId(void) const
Definition: node.cc:109
uint32_t GetSize(void) const
Returns the the size in bytes of the packet (including the zero-filled initial payload).
Definition: packet.h:852
Access to the IPv6 forwarding table, interfaces, and configuration.
Definition: ipv6.h:81
static const uint32_t packetSize
A suite of tests to run.
Definition: test.h:1343
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:283
encapsulates test code
Definition: test.h:1153
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:1937
channel
Definition: third.py:92
void RemoveAllPacketTags(void)
Remove all packet tags.
Definition: packet.cc:984
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.
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.
Ptr< T > GetObject(void) const
Get a pointer to the requested aggregated Object.
Definition: object.h:470
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 StartClient(Ptr< Node > clientNode)
Start the client node.
Ptr< Socket > m_socketServer
Socket on the server.
Ptr< Packet > Copy(void) const
performs a COW copy of the packet.
Definition: packet.cc:121
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 Install(std::string nodeName) const
Aggregate implementations of the ns3::Ipv4, ns3::Ipv6, ns3::Udp, and ns3::Tcp classes onto the provid...
void HandleReadClient(Ptr< Socket > socket)
Handles incoming packets in the client.
Describes an IPv6 address.
Definition: ipv6-address.h:49
uint32_t AddDevice(Ptr< NetDevice > device)
Associate a NetDevice to this node.
Definition: node.cc:130
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.
uint32_t CopyData(uint8_t *buffer, uint32_t size) const
Copy the packet contents to a byte buffer.
Definition: packet.cc:378
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:1278
void RemoveAllByteTags(void)
Remove all byte tags stored in this packet.
Definition: packet.cc:371
uint8_t * m_data
Data to be carried in the packet.
Describes an IPv6 prefix.
Definition: ipv6-address.h:455
virtual bool AddAddress(uint32_t interface, Ipv6InterfaceAddress address)=0
Add an address on the specified IPv6 interface.
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
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:1642
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.